1 package org.djunits.value;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.fail;
5
6 import java.lang.reflect.Constructor;
7 import java.lang.reflect.Field;
8 import java.lang.reflect.InvocationTargetException;
9 import java.lang.reflect.Method;
10
11 import org.djunits.unit.Unit;
12 import org.djunits.unit.quantity.Quantity;
13 import org.djunits.unit.scale.LinearScale;
14 import org.djunits.unit.si.SIPrefixes;
15 import org.djunits.unit.unitsystem.UnitSystem;
16 import org.djunits.util.ClassUtil;
17 import org.djunits.value.vdouble.scalar.base.AbstractDoubleScalar;
18 import org.djunits.value.vdouble.scalar.base.AbstractDoubleScalarAbs;
19 import org.djunits.value.vdouble.scalar.base.AbstractDoubleScalarRel;
20 import org.djunits.value.vdouble.scalar.base.DoubleScalar;
21 import org.djunits.value.vdouble.scalar.base.DoubleScalarInterface;
22 import org.djunits.value.vfloat.scalar.base.AbstractFloatScalar;
23 import org.djunits.value.vfloat.scalar.base.AbstractFloatScalarAbs;
24 import org.djunits.value.vfloat.scalar.base.AbstractFloatScalarRel;
25 import org.djunits.value.vfloat.scalar.base.FloatScalar;
26 import org.djunits.value.vfloat.scalar.base.FloatScalarInterface;
27 import org.junit.Assert;
28 import org.junit.Test;
29
30
31
32
33
34
35
36
37
38
39
40 public class ScalarOperationsTest
41 {
42
43
44
45
46
47
48
49
50
51
52
53 @Test
54 public final void scalarOperationsTest() throws NoSuchMethodException, InstantiationException, IllegalAccessException,
55 InvocationTargetException, NoSuchFieldException, SecurityException, IllegalArgumentException, ClassNotFoundException
56 {
57 doubleOrFloatScalarOperationsTest(true);
58 doubleOrFloatScalarOperationsTest(false);
59 }
60
61
62
63
64
65
66
67
68
69
70
71
72
73 private void doubleOrFloatScalarOperationsTest(final boolean doubleType)
74 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
75 NoSuchFieldException, SecurityException, IllegalArgumentException, ClassNotFoundException
76 {
77 final String upperType = doubleType ? "Double" : "Float";
78 final String type = upperType.toLowerCase();
79
80 for (int i = 0; i < CLASSNAMES.ABS_LIST.size(); i++)
81 {
82 String scalarNameAbs = CLASSNAMES.ABS_LIST.get(i);
83 String scalarNameRel = CLASSNAMES.REL_WITH_ABS_LIST.get(i);
84 String scalarClassNameAbs = doubleType ? scalarNameAbs : "Float" + scalarNameAbs;
85 String scalarClassNameRel = doubleType ? scalarNameRel : "Float" + scalarNameRel;
86 Class<?> scalarClassAbs = null;
87 Class<?> scalarClassRel = null;
88
89 try
90 {
91 scalarClassAbs = Class.forName("org.djunits.value.v" + type + ".scalar." + scalarClassNameAbs);
92 }
93 catch (ClassNotFoundException exception)
94 {
95 fail("Class Rel not found for " + upperType + "Scalar class " + "org.djunits.value.v" + type + ".scalar."
96 + scalarClassNameAbs);
97 }
98 try
99 {
100 scalarClassRel = Class.forName("org.djunits.value.v" + type + ".scalar." + scalarClassNameRel);
101 }
102 catch (ClassNotFoundException exception)
103 {
104 fail("Class Rel not found for " + upperType + "Scalar class " + "org.djunits.value.v" + type + ".scalar."
105 + scalarClassNameRel);
106 }
107 testMethods(scalarClassAbs, true, doubleType);
108 testMethods(scalarClassRel, false, doubleType);
109 }
110
111
112 for (String scalarName : CLASSNAMES.REL_LIST)
113 {
114 String scalarClassName = doubleType ? scalarName : "Float" + scalarName;
115 Class<?> scalarClassRel = null;
116 try
117 {
118 scalarClassRel = Class.forName("org.djunits.value.v" + type + ".scalar." + scalarClassName);
119 }
120 catch (ClassNotFoundException exception)
121 {
122 fail("Class Rel not found for " + upperType + "DoubleScalar class " + "org.djunits.value.v" + type + ".scalar."
123 + scalarClassName);
124 }
125 testMethods(scalarClassRel, false, doubleType);
126 }
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 private void testMethods(final Class<?> scalarClassAbsRel, final boolean isAbs, final boolean doubleType)
143 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
144 NoSuchFieldException, ClassNotFoundException
145 {
146 for (Method method : scalarClassAbsRel.getMethods())
147 {
148 if (method.getName().equals("times"))
149 {
150
151 testMultiplyOrDivideMethodAbsRel(scalarClassAbsRel, isAbs, method, true, doubleType);
152 }
153 else if (method.getName().equals("divide"))
154 {
155
156 testMultiplyOrDivideMethodAbsRel(scalarClassAbsRel, isAbs, method, false, doubleType);
157 }
158 }
159 testUnaryMethods(scalarClassAbsRel, isAbs, doubleType);
160 testStaticMethods(scalarClassAbsRel, isAbs, doubleType);
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 private void testMultiplyOrDivideMethodAbsRel(final Class<?> scalarClass, final boolean abs, final Method method,
177 final boolean multiply, final boolean doubleType) throws NoSuchMethodException, InstantiationException,
178 IllegalAccessException, InvocationTargetException, NoSuchFieldException
179 {
180 Class<?> relativeOrAbsoluteClass = null;
181 try
182 {
183 relativeOrAbsoluteClass = Class.forName("org.djunits.value." + (abs ? "Absolute" : "Relative"));
184 }
185 catch (ClassNotFoundException exception)
186 {
187 fail("Could not find org.djunits.value.Relative class");
188 }
189 Class<?>[] parTypes = method.getParameterTypes();
190 if (parTypes.length != 1)
191 {
192 fail("DoubleScalar class " + scalarClass.getName() + "." + method.getName() + "() has " + parTypes.length
193 + " parameters, <> 1");
194 }
195 Class<?> parameterClass = parTypes[0];
196 if (parameterClass.toString().equals("double") || parameterClass.toString().equals("float"))
197 {
198
199 return;
200 }
201 if (parameterClass.getSimpleName().startsWith("Abstract"))
202 {
203
204 return;
205 }
206 if (!relativeOrAbsoluteClass.isAssignableFrom(parameterClass))
207 {
208
209
210 Assert.fail("DoubleScalar class " + scalarClass.getName() + "." + method.getName() + "() has parameter with non-"
211 + relativeOrAbsoluteClass + " class: " + relativeOrAbsoluteClass.getName());
212 }
213
214 Class<?> returnClass = method.getReturnType();
215 if (!relativeOrAbsoluteClass.isAssignableFrom(returnClass))
216 {
217 Assert.fail("DoubleScalar class " + scalarClass.getName() + ".times() has return type with non-relative class: "
218 + returnClass.getName());
219 }
220
221
222 String returnSI = getCoefficients(getUnitClass(returnClass));
223
224
225
226
227
228
229
230
231
232 Constructor<?> constructor = scalarClass.getConstructor(double.class, getUnitClass(scalarClass));
233 if (abs)
234 {
235 fail("Absolute types should not have a multiply or divide method");
236 AbstractDoubleScalarAbs<?, ?, ?, ?> left = (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(123d,
237 getSIUnitInstance(getUnitClass(scalarClass), abs));
238
239 constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
240 AbstractDoubleScalarAbs<?, ?, ?, ?> right = (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(456d,
241 getSIUnitInstance(getUnitClass(parameterClass), abs));
242
243 double expectedValue = multiply ? 123d * 456 : 123d / 456;
244
245 if (multiply)
246 {
247 Method multiplyMethod = ClassUtil.resolveMethod(scalarClass, "times", new Class[] {parameterClass});
248 Object result = multiplyMethod.invoke(left, right);
249 double resultSI = ((AbstractDoubleScalarAbs<?, ?, ?, ?>) result).getSI();
250 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
251 }
252 else
253 {
254 Method divideMethod = ClassUtil.resolveMethod(scalarClass, "divide", new Class[] {parameterClass});
255 Object result = divideMethod.invoke(left, right);
256 double resultSI = ((AbstractDoubleScalarAbs<?, ?, ?, ?>) result).getSI();
257 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
258 }
259 }
260 else
261 {
262 if (doubleType)
263 {
264 AbstractDoubleScalarRel<?, ?> left = (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(123d,
265 getSIUnitInstance(getUnitClass(scalarClass), abs));
266
267 constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
268 AbstractDoubleScalarRel<?, ?> right = (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(456d,
269 getSIUnitInstance(getUnitClass(parameterClass), abs));
270
271 double expectedValue = multiply ? 123d * 456 : 123d / 456;
272
273 if (multiply)
274 {
275 Method multiplyMethod = ClassUtil.resolveMethod(scalarClass, "times", new Class[] {parameterClass});
276 Object result = multiplyMethod.invoke(left, right);
277 double resultSI = ((AbstractDoubleScalarRel<?, ?>) result).getSI();
278 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
279 }
280 else
281 {
282 Method divideMethod = ClassUtil.resolveMethod(scalarClass, "divide", new Class[] {parameterClass});
283 Object result = divideMethod.invoke(left, right);
284 double resultSI = ((AbstractDoubleScalarRel<?, ?>) result).getSI();
285 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
286 }
287 AbstractDoubleScalarRel<?, ?> result =
288 multiply ? DoubleScalar.multiply(left, right) : DoubleScalar.divide(left, right);
289
290 String resultCoefficients = result.getDisplayUnit().getQuantity().getSiDimensions().toString();
291 assertEquals(
292 "SI coefficients of result of " + left.getClass().getSimpleName() + " x "
293 + right.getClass().getSimpleName() + " should match expected SI coefficients",
294 resultCoefficients, returnSI);
295 }
296 else
297 {
298 AbstractFloatScalarRel<?, ?> left = (AbstractFloatScalarRel<?, ?>) constructor.newInstance(123f,
299 getSIUnitInstance(getUnitClass(scalarClass), abs));
300
301 constructor = parameterClass.getConstructor(double.class, getUnitClass(parameterClass));
302 AbstractFloatScalarRel<?, ?> right = (AbstractFloatScalarRel<?, ?>) constructor.newInstance(456f,
303 getSIUnitInstance(getUnitClass(parameterClass), abs));
304
305 float expectedValue = multiply ? 123f * 456 : 123f / 456;
306
307 if (multiply)
308 {
309 Method multiplyMethod = ClassUtil.resolveMethod(scalarClass, "times", new Class[] {parameterClass});
310 Object result = multiplyMethod.invoke(left, right);
311 double resultSI = ((AbstractFloatScalarRel<?, ?>) result).getSI();
312 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
313 }
314 else
315 {
316 Method divideMethod = ClassUtil.resolveMethod(scalarClass, "divide", new Class[] {parameterClass});
317 Object result = divideMethod.invoke(left, right);
318 float resultSI = ((AbstractFloatScalarRel<?, ?>) result).getSI();
319 assertEquals("Result of operation", expectedValue, resultSI, 0.01);
320 }
321 AbstractFloatScalarRel<?, ?> result =
322 multiply ? FloatScalar.multiply(left, right) : FloatScalar.divide(left, right);
323
324 String resultCoefficients = result.getDisplayUnit().getQuantity().getSiDimensions().toString();
325 assertEquals("SI coefficients of result should match expected SI coefficients", resultCoefficients, returnSI);
326 }
327 }
328 }
329
330
331
332
333
334
335
336
337 private String getCoefficients(final Class<?> clas) throws IllegalAccessException, NoSuchFieldException
338 {
339 Field si = clas.getField("SI");
340 Unit<?> u = ((Unit<?>) si.get(clas));
341 String r = u.getQuantity().getSiDimensions().toString();
342 return r;
343 }
344
345
346
347
348
349
350
351
352
353 private Unit<?> getSIUnitInstance(final Class<?> clas, final boolean isAbs)
354 throws NoSuchFieldException, IllegalAccessException
355 {
356 Field si = isAbs ? clas.getField("DEFAULT") : clas.getField("SI");
357 return ((Unit<?>) si.get(clas));
358 }
359
360
361
362
363
364
365 private Class<?> getUnitClass(final Class<?> scalarClass)
366 {
367 Constructor<?>[] constructors = scalarClass.getConstructors();
368 for (Constructor<?> constructor : constructors)
369 {
370 Class<?>[] parTypes = constructor.getParameterTypes();
371 if (parTypes.length == 2 && Unit.class.isAssignableFrom(parTypes[1]))
372 {
373 return parTypes[1];
374 }
375 }
376 Assert.fail("Could not find constructor with one unit for Scalar class " + scalarClass.getName());
377 return null;
378 }
379
380
381
382
383
384
385
386
387 private double verifyAbsRelPrecisionAndExtractSI(final boolean abs, final boolean doubleType, final Object o)
388 {
389 double result = Double.NaN;
390 if (doubleType)
391 {
392 if (!(o instanceof DoubleScalarInterface))
393 {
394 fail("object is not a DoubleScalar");
395 }
396 result = ((AbstractDoubleScalar<?, ?>) o).getSI();
397 }
398 else
399 {
400 if (!(o instanceof FloatScalarInterface))
401 {
402 fail("object is not a FloatScalar");
403 }
404 result = ((AbstractFloatScalar<?, ?>) o).getSI();
405 }
406 if (o instanceof Absolute)
407 {
408 if (!abs)
409 {
410 fail("Result should have been Absolute");
411 }
412 }
413 else if (o instanceof Relative)
414 {
415 if (abs)
416 {
417 fail("Result should have been Relative");
418 }
419 }
420 else
421 {
422 fail("Result is neither Absolute, nor Relative");
423 }
424 return result;
425 }
426
427
428
429
430
431
432
433
434
435
436
437
438 @SuppressWarnings({"rawtypes", "unchecked"})
439 private void testUnaryMethods(final Class<?> scalarClass, final boolean abs, final boolean doubleType)
440 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
441 NoSuchFieldException, ClassNotFoundException
442 {
443 double value = 1.23456;
444 Constructor<?> constructor =
445 scalarClass.getConstructor(doubleType ? double.class : float.class, getUnitClass(scalarClass));
446 Object left;
447 if (doubleType)
448 {
449 left = abs
450 ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(value,
451 getSIUnitInstance(getUnitClass(scalarClass), abs))
452 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(value,
453 getSIUnitInstance(getUnitClass(scalarClass), abs));
454
455 Constructor<?>[] constructors = scalarClass.getConstructors();
456 for (Constructor<?> c : constructors)
457 {
458 Class<?>[] parTypes = c.getParameterTypes();
459 if (parTypes.length == 1)
460 {
461 AbstractDoubleScalar<?, ?> newInstance = (AbstractDoubleScalar<?, ?>) c.newInstance(left);
462 assertEquals("Result of constructor should be equal to original", value,
463 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, newInstance), 0.01);
464 }
465 }
466 }
467 else
468 {
469 left = abs
470 ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance((float) value,
471 getSIUnitInstance(getUnitClass(scalarClass), abs))
472 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance((float) value,
473 getSIUnitInstance(getUnitClass(scalarClass), abs));
474
475 Constructor<?>[] constructors = scalarClass.getConstructors();
476 for (Constructor<?> c : constructors)
477 {
478 Class<?>[] parTypes = c.getParameterTypes();
479 if (parTypes.length == 1)
480 {
481
482 AbstractFloatScalar<?, ?> newInstance = (AbstractFloatScalar<?, ?>) c.newInstance(left);
483 assertEquals("Result of constructor should be equal to original", value,
484 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, newInstance), 0.01);
485 }
486 }
487 }
488 Object result;
489
490 Method ceil = ClassUtil.resolveMethod(scalarClass, "ceil", new Class[] {});
491 result = ceil.invoke(left);
492 assertEquals("Result of operation", Math.ceil(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
493
494 Method floor = ClassUtil.resolveMethod(scalarClass, "floor", new Class[] {});
495 result = floor.invoke(left);
496 assertEquals("Result of operation", Math.floor(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
497 0.01);
498
499 Method rint = ClassUtil.resolveMethod(scalarClass, "rint", new Class[] {});
500 result = rint.invoke(left);
501 assertEquals("Result of operation", Math.rint(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
502
503 if (!abs)
504 {
505 Method methodAbs = ClassUtil.resolveMethod(scalarClass, "abs", new Class[] {});
506 result = methodAbs.invoke(left);
507 assertEquals("Result of operation", Math.abs(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
508 0.01);
509 }
510
511 if (scalarClass.getName().contains("Dimensionless"))
512 {
513 Method asin = ClassUtil.resolveMethod(scalarClass, "asin", new Class[] {});
514 result = asin.invoke(left);
515 assertEquals("Result of operation", Math.asin(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
516 0.01);
517
518 Method acos = ClassUtil.resolveMethod(scalarClass, "acos", new Class[] {});
519 result = acos.invoke(left);
520 assertEquals("Result of operation", Math.acos(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
521 0.01);
522
523 Method atan = ClassUtil.resolveMethod(scalarClass, "atan", new Class[] {});
524 result = atan.invoke(left);
525 assertEquals("Result of operation", Math.atan(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
526 0.01);
527
528 Method cbrt = ClassUtil.resolveMethod(scalarClass, "cbrt", new Class[] {});
529 result = cbrt.invoke(left);
530 assertEquals("Result of operation", Math.cbrt(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
531 0.01);
532
533 Method cos = ClassUtil.resolveMethod(scalarClass, "cos", new Class[] {});
534 result = cos.invoke(left);
535 assertEquals("Result of operation", Math.cos(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
536 0.01);
537
538 Method cosh = ClassUtil.resolveMethod(scalarClass, "cosh", new Class[] {});
539 result = cosh.invoke(left);
540 assertEquals("Result of operation", Math.cosh(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
541 0.01);
542
543 Method exp = ClassUtil.resolveMethod(scalarClass, "exp", new Class[] {});
544 result = exp.invoke(left);
545 assertEquals("Result of operation", Math.exp(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
546 0.01);
547
548 Method expm1 = ClassUtil.resolveMethod(scalarClass, "expm1", new Class[] {});
549 result = expm1.invoke(left);
550 assertEquals("Result of operation", Math.expm1(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
551 0.01);
552
553 Method log = ClassUtil.resolveMethod(scalarClass, "log", new Class[] {});
554 result = log.invoke(left);
555 assertEquals("Result of operation", Math.log(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
556 0.01);
557
558 Method log10 = ClassUtil.resolveMethod(scalarClass, "log10", new Class[] {});
559 result = log10.invoke(left);
560 assertEquals("Result of operation", Math.log10(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
561 0.01);
562
563 Method log1p = ClassUtil.resolveMethod(scalarClass, "log1p", new Class[] {});
564 result = log1p.invoke(left);
565 assertEquals("Result of operation", Math.log1p(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
566 0.01);
567
568 Method signum = ClassUtil.resolveMethod(scalarClass, "signum", new Class[] {});
569 result = signum.invoke(left);
570 assertEquals("Result of operation", Math.signum(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
571 0.01);
572
573 Method sin = ClassUtil.resolveMethod(scalarClass, "sin", new Class[] {});
574 result = sin.invoke(left);
575 assertEquals("Result of operation", Math.sin(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
576 0.01);
577
578 Method sinh = ClassUtil.resolveMethod(scalarClass, "sinh", new Class[] {});
579 result = sinh.invoke(left);
580 assertEquals("Result of operation", Math.sinh(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
581 0.01);
582
583 Method sqrt = ClassUtil.resolveMethod(scalarClass, "sqrt", new Class[] {});
584 result = sqrt.invoke(left);
585 assertEquals("Result of operation", Math.sqrt(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
586 0.01);
587
588 Method tan = ClassUtil.resolveMethod(scalarClass, "tan", new Class[] {});
589 result = tan.invoke(left);
590 assertEquals("Result of operation", Math.tan(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
591 0.01);
592
593 Method tanh = ClassUtil.resolveMethod(scalarClass, "tanh", new Class[] {});
594 result = tanh.invoke(left);
595 assertEquals("Result of operation", Math.tanh(value), verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
596 0.01);
597
598 Method inv = ClassUtil.resolveMethod(scalarClass, "inv", new Class[] {});
599 result = inv.invoke(left);
600 assertEquals("Result of operation", 1 / value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
601
602 Method pow = ClassUtil.resolveMethod(scalarClass, "pow", new Class[] {double.class});
603 result = pow.invoke(left, Math.PI);
604 assertEquals("Result of operation", Math.pow(value, Math.PI),
605 verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result), 0.01);
606 }
607
608 Object compatibleRight = null;
609
610 if (!scalarClass.getName().contains("Dimensionless") && !scalarClass.getName().contains("AbsoluteTemperature")
611 && !scalarClass.getName().contains("Position") && !scalarClass.getName().contains("Time")
612 && !scalarClass.getName().contains("Direction"))
613 {
614
615 Class<?> unitClass = getUnitClass(scalarClass);
616 UnitSystem unitSystem = UnitSystem.SI_DERIVED;
617
618
619 Constructor<?> unitConstructor = unitClass.getConstructor();
620 Unit newUnit = (Unit) unitConstructor.newInstance();
621 Method buildMethod = ClassUtil.resolveMethod(Unit.class, "build", Unit.Builder.class);
622 Unit.Builder<?> builder = new Unit.Builder<>();
623 builder.setId("7abbr");
624 builder.setName("7fullName");
625 builder.setUnitSystem(unitSystem);
626 builder.setScale(new LinearScale(7));
627 builder.setQuantity((Quantity) getSIUnitInstance(unitClass, false).getQuantity());
628 builder.setSiPrefixes(SIPrefixes.NONE, 1.0);
629 buildMethod.setAccessible(true);
630 buildMethod.invoke(newUnit, builder);
631
632
633 if (doubleType)
634 {
635 compatibleRight = abs ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(value, newUnit)
636 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(value, newUnit);
637 }
638 else
639 {
640 compatibleRight = abs ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance((float) value, newUnit)
641 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance((float) value, newUnit);
642 }
643
644 newUnit.getQuantity().unregister(newUnit);
645 }
646 if (!abs)
647 {
648 Method times = ClassUtil.resolveMethod(scalarClass, "times", new Class[] {double.class});
649 result = doubleType ? times.invoke(left, Math.PI) : times.invoke(left, (float) Math.PI);
650 assertEquals("Result of operation", Math.PI * value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
651 0.01);
652 if (!doubleType)
653 {
654 times = ClassUtil.resolveMethod(scalarClass, "times", new Class[] {float.class});
655 result = doubleType ? times.invoke(left, Math.PI) : times.invoke(left, (float) Math.PI);
656 assertEquals("Result of operation", Math.PI * value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
657 0.01);
658 }
659
660 Method divide = ClassUtil.resolveMethod(scalarClass, "divide", new Class[] {double.class});
661 result = doubleType ? divide.invoke(left, Math.PI) : divide.invoke(left, (float) Math.PI);
662 assertEquals("Result of operation", value / Math.PI, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
663 0.01);
664 if (!doubleType)
665 {
666 divide = ClassUtil.resolveMethod(scalarClass, "divide", new Class[] {float.class});
667 result = doubleType ? divide.invoke(left, Math.PI) : divide.invoke(left, (float) Math.PI);
668 assertEquals("Result of operation", value / Math.PI, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
669 0.01);
670 }
671
672 Method plus = ClassUtil.resolveMethod(scalarClass, "plus", new Class[] {scalarClass});
673 result = plus.invoke(left, left);
674 assertEquals("Result of operation", value + value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
675 0.01);
676
677 if (null != compatibleRight)
678 {
679 result = plus.invoke(left, compatibleRight);
680 assertEquals("Result of mixed operation", 8 * value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
681 0.01);
682
683
684
685 plus = ClassUtil.resolveMethod(scalarClass, "plus", new Class[] {compatibleRight.getClass().getSuperclass()});
686 result = plus.invoke(compatibleRight, left);
687 assertEquals("Result of mixed operation", 8 * value, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
688 0.01);
689 if (scalarClass.getName().contains("$Rel"))
690 {
691
692 String absScalarClassName = scalarClass.getName().replace("$Rel", "$Abs");
693 Class<?> absScalarClass = Class.forName(absScalarClassName);
694 Constructor<?> absScalarConstructor = absScalarClass.getConstructor(doubleType ? double.class : float.class,
695 getUnitClass(absScalarClass));
696 Object absOperand = null;
697
698 if (doubleType)
699 {
700 absOperand =
701 absScalarConstructor.newInstance(value, getSIUnitInstance(getUnitClass(absScalarClass), true));
702 }
703 else
704 {
705 absOperand = absScalarConstructor.newInstance((float) value,
706 getSIUnitInstance(getUnitClass(absScalarClass), true));
707 }
708
709 plus = ClassUtil.resolveMethod(absScalarClass, "plus", scalarClass);
710 result = plus.invoke(absOperand, left);
711 assertEquals("Result of mixed abs + rel", 2 * value,
712 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
713 Method toAbs = compatibleRight.getClass().getMethod("toAbs");
714 Object absCompatible = toAbs.invoke(compatibleRight);
715 result = plus.invoke(absCompatible, left);
716 assertEquals("Result of mixed compatible abs + rel", 8 * value,
717 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
718
719 plus = ClassUtil.resolveMethod(scalarClass, "plus", absScalarClass);
720 result = plus.invoke(left, absOperand);
721 assertEquals("Result of mixed rel + abs", 2 * value,
722 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
723 result = plus.invoke(left, absCompatible);
724 assertEquals("Result of mixed rel + compatible abs", 8 * value,
725 verifyAbsRelPrecisionAndExtractSI(true, doubleType, result), 0.01);
726 }
727 }
728 }
729
730 Method minus = ClassUtil.resolveMethod(scalarClass, "minus", new Class[] {scalarClass});
731 result = minus.invoke(left, left);
732 assertEquals("Result of minus", 0, verifyAbsRelPrecisionAndExtractSI(false, doubleType, result), 0.01);
733 if (null != compatibleRight)
734 {
735 result = minus.invoke(left, compatibleRight);
736 assertEquals("Result of minus with compatible arg for " + left + " and " + compatibleRight, -6 * value,
737 verifyAbsRelPrecisionAndExtractSI(false, doubleType, result), 0.01);
738 }
739 if (scalarClass.getName().contains("$Rel") || scalarClass.getName().contains("$Abs"))
740 {
741
742 String absScalarClassName = scalarClass.getName().replace("$Rel", "$Abs");
743 Class<?> absScalarClass = Class.forName(absScalarClassName);
744 Constructor<?> absScalarConstructor =
745 absScalarClass.getConstructor(doubleType ? double.class : float.class, getUnitClass(absScalarClass));
746 Object absOperand = null;
747
748 if (doubleType)
749 {
750 absOperand = absScalarConstructor.newInstance(value, getSIUnitInstance(getUnitClass(absScalarClass), true));
751 }
752 else
753 {
754 absOperand =
755 absScalarConstructor.newInstance((float) value, getSIUnitInstance(getUnitClass(absScalarClass), true));
756 }
757 minus = ClassUtil.resolveMethod(absScalarClass, "minus", scalarClass);
758 result = minus.invoke(absOperand, left);
759 assertEquals("Result of abs or rel minus rel", 0, verifyAbsRelPrecisionAndExtractSI(!abs, doubleType, result),
760 0.01);
761 if (null != compatibleRight && scalarClass.getName().contains("$Rel"))
762 {
763 Method toAbs = compatibleRight.getClass().getMethod("toAbs");
764 Object absCompatible = toAbs.invoke(compatibleRight);
765 result = minus.invoke(absCompatible, left);
766 assertEquals("Result of compatible abs or rel minus rel", 6 * value,
767 verifyAbsRelPrecisionAndExtractSI(!abs, doubleType, result), 0.01);
768 }
769
770 }
771 }
772
773
774
775
776
777
778
779
780
781
782
783
784 private void testStaticMethods(final Class<?> scalarClass, final boolean abs, final boolean doubleType)
785 throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException,
786 NoSuchFieldException
787 {
788 Constructor<?> constructor = scalarClass.getConstructor(double.class, getUnitClass(scalarClass));
789 if (doubleType)
790 {
791 double zeroValue = 1.23456;
792 AbstractDoubleScalar<?,
793 ?> zero = abs
794 ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(zeroValue,
795 getSIUnitInstance(getUnitClass(scalarClass), abs))
796 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(zeroValue,
797 getSIUnitInstance(getUnitClass(scalarClass), abs));
798 double oneValue = 3.45678;
799 AbstractDoubleScalar<?,
800 ?> one = abs
801 ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(oneValue,
802 getSIUnitInstance(getUnitClass(scalarClass), abs))
803 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(oneValue,
804 getSIUnitInstance(getUnitClass(scalarClass), abs));
805 for (double ratio : new double[] {-5, -1, 0, 0.3, 1, 2, 10})
806 {
807 double expectedResult = (1.0 - ratio) * zeroValue + ratio * oneValue;
808 Method interpolate =
809 ClassUtil.resolveMethod(scalarClass, "interpolate", scalarClass, scalarClass, double.class);
810 AbstractDoubleScalar<?, ?> result;
811 result = (AbstractDoubleScalar<?, ?>) interpolate.invoke(null, zero, one, ratio);
812 assertEquals("Result of operation", expectedResult, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
813 0.01);
814 }
815 double biggestValue = 345.678;
816 AbstractDoubleScalar<?,
817 ?> biggest = abs
818 ? (AbstractDoubleScalarAbs<?, ?, ?, ?>) constructor.newInstance(biggestValue,
819 getSIUnitInstance(getUnitClass(scalarClass), abs))
820 : (AbstractDoubleScalarRel<?, ?>) constructor.newInstance(biggestValue,
821 getSIUnitInstance(getUnitClass(scalarClass), abs));
822 Method max = ClassUtil.resolveMethod(scalarClass, "max", scalarClass, scalarClass);
823 AbstractDoubleScalar<?, ?> result = (AbstractDoubleScalar<?, ?>) max.invoke(null, zero, one);
824 assertEquals("max returns object with maximum value", one, result);
825 result = (AbstractDoubleScalar<?, ?>) max.invoke(null, one, zero);
826 assertEquals("max returns object with maximum value", one, result);
827
828 Class<?> emptyClassArrayClass = java.lang.reflect.Array.newInstance(scalarClass, 0).getClass();
829 max = ClassUtil.resolveMethod(scalarClass, "max", scalarClass, scalarClass, emptyClassArrayClass);
830 AbstractDoubleScalar<?, ?>[] additionalArguments =
831 (AbstractDoubleScalar<?, ?>[]) java.lang.reflect.Array.newInstance(scalarClass, 1);
832 additionalArguments[0] = biggest;
833 result = (AbstractDoubleScalar<?, ?>) max.invoke(null, zero, one, additionalArguments);
834 assertEquals("max return object with maximum value", biggest, result);
835 result = (AbstractDoubleScalar<?, ?>) max.invoke(null, one, zero, additionalArguments);
836 assertEquals("max return object with maximum value", biggest, result);
837 additionalArguments[0] = zero;
838 result = (AbstractDoubleScalar<?, ?>) max.invoke(null, biggest, zero, additionalArguments);
839 assertEquals("max return object with maximum value", biggest, result);
840
841 Method min = ClassUtil.resolveMethod(scalarClass, "min", scalarClass, scalarClass);
842 result = (AbstractDoubleScalar<?, ?>) min.invoke(null, zero, one);
843 assertEquals("min returns object with maximum value", zero, result);
844 result = (AbstractDoubleScalar<?, ?>) min.invoke(null, one, zero);
845 assertEquals("min returns object with maximum value", zero, result);
846 min = ClassUtil.resolveMethod(scalarClass, "min", scalarClass, scalarClass, emptyClassArrayClass);
847 result = (AbstractDoubleScalar<?, ?>) min.invoke(null, one, biggest, additionalArguments);
848 assertEquals("min return object with minimum value", zero, result);
849 result = (AbstractDoubleScalar<?, ?>) min.invoke(null, biggest, one, additionalArguments);
850 assertEquals("min return object with minimum value", zero, result);
851 additionalArguments[0] = biggest;
852 result = (AbstractDoubleScalar<?, ?>) min.invoke(null, zero, one, additionalArguments);
853 assertEquals("min return object with minimum value", zero, result);
854
855 Method valueOf = ClassUtil.resolveMethod(scalarClass, "valueOf", String.class);
856 String string = zero.toString();
857 result = (AbstractDoubleScalar<?, ?>) valueOf.invoke(null, string);
858 assertEquals("valueOf toString returns a decent approximation of the input", zeroValue, result.getSI(), 0.001);
859 try
860 {
861 valueOf.invoke(null, (String) null);
862 fail("Null string in valueOf should have thrown an IllegalArgumentException (which may have been converted "
863 + "into an InvocationTargetException)");
864 }
865 catch (IllegalArgumentException | InvocationTargetException iae)
866 {
867
868 }
869
870 try
871 {
872 valueOf.invoke(null, "");
873 fail("Empty string in valueOf should have thrown an IllegalArgumentException");
874 }
875 catch (IllegalArgumentException | InvocationTargetException iae)
876 {
877
878 }
879
880 try
881 {
882 valueOf.invoke(null, "NONSENSEVALUE");
883 fail("Nonsense string in valueOf should have thrown an IllegalArgumentException");
884 }
885 catch (IllegalArgumentException | InvocationTargetException iae)
886 {
887
888 }
889
890 try
891 {
892 valueOf.invoke(null, "1.0 xyzuwv");
893 fail("Nonsense unit string in valueOf argument should have thrown an IllegalArgumentException");
894 }
895 catch (IllegalArgumentException | InvocationTargetException iae)
896 {
897
898 }
899
900 Method instantiateSI = ClassUtil.resolveMethod(scalarClass, "instantiateSI", double.class);
901 result = (AbstractDoubleScalar<?, ?>) instantiateSI.invoke(null, zeroValue);
902 assertEquals("SI value was correctly set", zeroValue, result.getSI(), 0.0001);
903 }
904 else
905 {
906 float zeroValue = 1.23456f;
907 AbstractFloatScalar<?,
908 ?> zero = abs
909 ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance(zeroValue,
910 getSIUnitInstance(getUnitClass(scalarClass), abs))
911 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance(zeroValue,
912 getSIUnitInstance(getUnitClass(scalarClass), abs));
913 float oneValue = 3.45678f;
914 AbstractFloatScalar<?,
915 ?> one = abs
916 ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance(oneValue,
917 getSIUnitInstance(getUnitClass(scalarClass), abs))
918 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance(oneValue,
919 getSIUnitInstance(getUnitClass(scalarClass), abs));
920 for (float ratio : new float[] {-5, -1, 0, 0.3f, 1, 2, 10})
921 {
922 float expectedResult = (1.0f - ratio) * zeroValue + ratio * oneValue;
923 Method interpolate = ClassUtil.resolveMethod(scalarClass, "interpolate", scalarClass, scalarClass, float.class);
924 AbstractFloatScalar<?, ?> result;
925 result = (AbstractFloatScalar<?, ?>) interpolate.invoke(null, zero, one, ratio);
926 assertEquals("Result of operation", expectedResult, verifyAbsRelPrecisionAndExtractSI(abs, doubleType, result),
927 0.01);
928 }
929 float biggestValue = 345.678f;
930 AbstractFloatScalar<?,
931 ?> biggest = abs
932 ? (AbstractFloatScalarAbs<?, ?, ?, ?>) constructor.newInstance(biggestValue,
933 getSIUnitInstance(getUnitClass(scalarClass), abs))
934 : (AbstractFloatScalarRel<?, ?>) constructor.newInstance(biggestValue,
935 getSIUnitInstance(getUnitClass(scalarClass), abs));
936 Method max = ClassUtil.resolveMethod(scalarClass, "max", scalarClass, scalarClass);
937 AbstractFloatScalar<?, ?> result = (AbstractFloatScalar<?, ?>) max.invoke(null, zero, one);
938 assertEquals("max return object with maximum value", one, result);
939 result = (AbstractFloatScalar<?, ?>) max.invoke(null, one, zero);
940 assertEquals("max return object with maximum value", one, result);
941
942 Class<?> emptyClassArrayClass = java.lang.reflect.Array.newInstance(scalarClass, 0).getClass();
943 max = ClassUtil.resolveMethod(scalarClass, "max", scalarClass, scalarClass, emptyClassArrayClass);
944 AbstractFloatScalar<?, ?>[] additionalArguments =
945 (AbstractFloatScalar<?, ?>[]) java.lang.reflect.Array.newInstance(scalarClass, 1);
946 additionalArguments[0] = biggest;
947 result = (AbstractFloatScalar<?, ?>) max.invoke(null, zero, one, additionalArguments);
948 assertEquals("max return object with maximum value", biggest, result);
949 result = (AbstractFloatScalar<?, ?>) max.invoke(null, one, zero, additionalArguments);
950 assertEquals("max return object with maximum value", biggest, result);
951 additionalArguments[0] = zero;
952 result = (AbstractFloatScalar<?, ?>) max.invoke(null, biggest, zero, additionalArguments);
953 assertEquals("max return object with maximum value", biggest, result);
954
955 Method min = ClassUtil.resolveMethod(scalarClass, "min", scalarClass, scalarClass);
956 result = (AbstractFloatScalar<?, ?>) min.invoke(null, zero, one);
957 assertEquals("min returns object with maximum value", zero, result);
958 result = (AbstractFloatScalar<?, ?>) min.invoke(null, one, zero);
959 assertEquals("min returns object with maximum value", zero, result);
960 min = ClassUtil.resolveMethod(scalarClass, "min", scalarClass, scalarClass, emptyClassArrayClass);
961 result = (AbstractFloatScalar<?, ?>) min.invoke(null, one, biggest, additionalArguments);
962 assertEquals("min return object with minimum value", zero, result);
963 result = (AbstractFloatScalar<?, ?>) min.invoke(null, biggest, one, additionalArguments);
964 assertEquals("min return object with minimum value", zero, result);
965 additionalArguments[0] = biggest;
966 result = (AbstractFloatScalar<?, ?>) min.invoke(null, zero, one, additionalArguments);
967 assertEquals("min return object with minimum value", zero, result);
968
969 Method valueOf = ClassUtil.resolveMethod(scalarClass, "valueOf", String.class);
970 String string = zero.toString();
971 result = (AbstractFloatScalar<?, ?>) valueOf.invoke(null, string);
972 assertEquals("valueOf toString returns a decent approximation of the input", zeroValue, result.getSI(), 0.001);
973 try
974 {
975 valueOf.invoke(null, (String) null);
976 fail("Null string in valueOf should have thrown an IllegalArgumentException (which may have been converted "
977 + "into an InvocationTargetException)");
978 }
979 catch (IllegalArgumentException | InvocationTargetException iae)
980 {
981
982 }
983
984 try
985 {
986 valueOf.invoke(null, "");
987 fail("Empty string in valueOf should have thrown an IllegalArgumentException");
988 }
989 catch (IllegalArgumentException | InvocationTargetException iae)
990 {
991
992 }
993
994 try
995 {
996 valueOf.invoke(null, "NONSENSEVALUE");
997 fail("Nonsense string in valueOf should have thrown an IllegalArgumentException");
998 }
999 catch (IllegalArgumentException | InvocationTargetException iae)
1000 {
1001
1002 }
1003
1004 try
1005 {
1006 valueOf.invoke(null, "1.0 xyzuwv");
1007 fail("Nonsense string in valueOf should have thrown an IllegalArgumentException");
1008 }
1009 catch (IllegalArgumentException | InvocationTargetException iae)
1010 {
1011
1012 }
1013
1014 Method instantiateSI = ClassUtil.resolveMethod(scalarClass, "instantiateSI", float.class);
1015 result = (AbstractFloatScalar<?, ?>) instantiateSI.invoke(null, zeroValue);
1016 assertEquals("SI value was correctly set", zeroValue, result.getSI(), 0.0001);
1017 }
1018 }
1019
1020 }