1   /* Copyright 2002-2022 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.utils.units;
18  
19  import org.hipparchus.fraction.Fraction;
20  import org.hipparchus.util.FastMath;
21  import org.junit.Assert;
22  import org.junit.Test;
23  import org.orekit.errors.OrekitException;
24  import org.orekit.errors.OrekitMessages;
25  import org.orekit.utils.Constants;
26  
27  /**
28   * Unit tests for {@link Lexer}.
29   *
30   * @author Luc Maisonobe
31   */
32  public class UnitTest {
33  
34      @Test
35      public void testTime() {
36          Assert.assertEquals(       1.0, Unit.SECOND.toSI(1.0), 1.0e-10);
37          Assert.assertEquals(      60.0, Unit.MINUTE.toSI(1.0), 1.0e-10);
38          Assert.assertEquals(    3600.0, Unit.HOUR.toSI(1.0),   1.0e-10);
39          Assert.assertEquals(   86400.0, Unit.DAY.toSI(1.0),    1.0e-10);
40          Assert.assertEquals(31557600.0, Unit.YEAR.toSI(1.0),   1.0e-10);
41          Assert.assertEquals(1.0,        Unit.SECOND.fromSI(     1.0), 1.0e-10);
42          Assert.assertEquals(1.0,        Unit.MINUTE.fromSI(    60.0), 1.0e-10);
43          Assert.assertEquals(1.0,        Unit.HOUR.fromSI(    3600.0), 1.0e-10);
44          Assert.assertEquals(1.0,        Unit.DAY.fromSI(    86400.0), 1.0e-10);
45          Assert.assertEquals(1.0,        Unit.YEAR.fromSI(31557600.0), 1.0e-10);
46          Assert.assertEquals(365.25,     Unit.DAY.fromSI(Unit.YEAR.toSI(1.0)), 1.0e-10);
47      }
48  
49      @Test
50      public void testSI() {
51          Assert.assertTrue(Unit.PERCENT.sameDimensionSI().sameDimension(Unit.ONE));
52          Assert.assertEquals("1", Unit.PERCENT.sameDimensionSI().getName());
53          Assert.assertEquals("m³.s⁻²", Unit.parse("km**3/s**2").sameDimensionSI().getName());
54          Assert.assertEquals("m⁻³.s⁻⁶.rad^(2/5)", Unit.parse("µas^(2/5)/(h**(2)×m)³").sameDimensionSI().getName());
55          
56      }
57  
58      @Test
59      public void testEquals() {
60          final Unit u1 = Unit.parse("kg/m³");
61          final Unit u2 = Unit.parse("kg/m^3");
62          Assert.assertNotSame(u1, u2);
63          Assert.assertEquals(u1, u2);
64          Assert.assertNotEquals(u1.getName(), u2.getName());
65          Assert.assertNotEquals(u1, Unit.parse("A").alias(u1.getName()));
66          Assert.assertNotEquals(u1, null);
67          Assert.assertNotEquals(u1, u1.getName());
68          Assert.assertEquals(19160943, u1.hashCode());
69      }
70  
71      @Test
72      public void testReference() {                                
73          checkReference(Unit.NONE,                        "n/a",                     1.0,  0,  0,  0,  0, 0);
74          checkReference(Unit.ONE,                           "1",                     1.0,  0,  0,  0,  0, 0);
75          checkReference(Unit.PERCENT,                       "%",                    0.01,  0,  0,  0,  0, 0);
76          checkReference(Unit.SECOND,                        "s",                     1.0,  0,  0,  1,  0, 0);
77          checkReference(Unit.MINUTE,                      "min",                    60.0,  0,  0,  1,  0, 0);
78          checkReference(Unit.HOUR,                          "h",                  3600.0,  0,  0,  1,  0, 0);
79          checkReference(Unit.DAY,                           "d",                 86400.0,  0,  0,  1,  0, 0);
80          checkReference(Unit.YEAR,                          "a",              31557600.0,  0,  0,  1,  0, 0);
81          checkReference(Unit.HERTZ,                        "Hz",                     1.0,  0,  0, -1,  0, 0);
82          checkReference(Unit.METRE,                         "m",                     1.0,  0,  1,  0,  0, 0);
83          checkReference(Unit.KILOMETRE,                    "km",                  1000.0,  0,  1,  0,  0, 0);
84          checkReference(Unit.KILOGRAM,                     "kg",                     1.0,  1,  0,  0,  0, 0);
85          checkReference(Unit.GRAM,                          "g",                   0.001,  1,  0,  0,  0, 0);
86          checkReference(Unit.AMPERE,                        "A",                     1.0,  0,  0,  0,  1, 0);
87          checkReference(Unit.RADIAN,                      "rad",                     1.0,  0,  0,  0,  0, 1);
88          checkReference(Unit.DEGREE,                        "°",  FastMath.PI /    180.0,  0,  0,  0,  0, 1);
89          checkReference(Unit.ARC_MINUTE,                    "′",  FastMath.PI /  10800.0,  0,  0,  0,  0, 1);
90          checkReference(Unit.ARC_SECOND,                    "″",  FastMath.PI / 648000.0,  0,  0,  0,  0, 1);
91          checkReference(Unit.REVOLUTION,                   "rev",      2.0 * FastMath.PI,  0,  0,  0,  0, 1);
92          checkReference(Unit.NEWTON,                        "N",                     1.0,  1,  1, -2,  0, 0);
93          checkReference(Unit.PASCAL,                       "Pa",                     1.0,  1, -1, -2,  0, 0);
94          checkReference(Unit.BAR,                         "bar",                100000.0,  1, -1, -2,  0, 0);
95          checkReference(Unit.JOULE,                         "J",                     1.0,  1,  2, -2,  0, 0);
96          checkReference(Unit.WATT,                          "W",                     1.0,  1,  2, -3,  0, 0);
97          checkReference(Unit.COULOMB,                       "C",                     1.0,  0,  0,  1,  1, 0);
98          checkReference(Unit.VOLT,                          "V",                     1.0,  1,  2, -3, -1, 0);
99          checkReference(Unit.OHM,                           "Ω",                     1.0,  1,  2, -3, -2, 0);
100         checkReference(Unit.TESLA,                         "T",                     1.0,  1,  0, -2, -1, 0);
101         checkReference(Unit.SOLAR_FLUX_UNIT,              "sfu",                1.0e-22,  1,  0, -2,  0, 0);
102         checkReference(Unit.TOTAL_ELECTRON_CONTENT_UNIT, "TECU",                 1.0e16,  0, -2,  0,  0, 0);
103 
104     }
105 
106     private void checkReference(final Unit unit, final String name, final double scale,
107                                 final int mass, final int length, final int time,
108                                 final int current, final int angle) {
109         Assert.assertEquals(name, unit.toString());
110         Assert.assertEquals(scale, unit.getScale(), 1.0e-10);
111         Assert.assertEquals(new Fraction(mass),     unit.getMass());
112         Assert.assertEquals(new Fraction(length),   unit.getLength());
113         Assert.assertEquals(new Fraction(time),     unit.getTime());
114         Assert.assertEquals(new Fraction(current),  unit.getCurrent());
115         Assert.assertEquals(new Fraction(angle),    unit.getAngle());
116     }
117 
118     @Test
119     public void testNotAUnit() {
120         Assert.assertSame(Unit.NONE, Unit.parse("n/a"));
121     }
122 
123     @Test
124     public void testOneUnit() {
125         checkReference("1",
126                        1.0,
127                        Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO);
128     }
129 
130     @Test
131     public void testND() {
132         // nd does not mean "not defined", but nano-day…
133         checkReference("nd",
134                        Prefix.NANO.getFactor() * Constants.JULIAN_DAY,
135                        Fraction.ZERO, Fraction.ZERO, Fraction.ONE, Fraction.ZERO);
136     }
137 
138     @Test
139     public void testPredefinedUnit() {
140         checkReference("MHz",
141                        1.0e6,
142                        Fraction.ZERO, Fraction.ZERO, Fraction.MINUS_ONE, Fraction.ZERO);
143     }
144 
145     @Test
146     public void testSquareRoot() {
147         checkReference("km/√d",
148                        1000.0 / FastMath.sqrt(Constants.JULIAN_DAY),
149                        Fraction.ZERO, Fraction.ONE, new Fraction(-1, 2), Fraction.ZERO);
150     }
151 
152     @Test
153     public void testChain() {
154         checkReference("kg.m^(3/4).s⁻¹",
155                        1.0,
156                        Fraction.ONE, new Fraction(3, 4), Fraction.MINUS_ONE, Fraction.ZERO);
157     }
158 
159     @Test
160     public void testExponents() {
161         checkReference("µas^⅖/(h**(2)×m)³",
162                        FastMath.pow(FastMath.toRadians(1.0 / 3.6e9), 0.4) / FastMath.pow(3600, 6),
163                        Fraction.ZERO, new Fraction(-3, 1), new Fraction(-6, 1), new Fraction(2, 5));
164     }
165 
166     @Test
167     public void testCompoundInSquareRoot() {
168         checkReference("km/√(kg.s)",
169                        1000.0,
170                        new Fraction(-1, 2), Fraction.ONE, new Fraction(-1, 2), Fraction.ZERO);
171     }
172 
173     @Test
174     public void testLeftAssociativity() {
175         checkReference("(kg/m)/s²",
176                        1.0,
177                        Fraction.ONE, Fraction.MINUS_ONE, new Fraction(-2), Fraction.ZERO);
178         checkReference("kg/(m/s²)",
179                        1.0,
180                        Fraction.ONE, Fraction.MINUS_ONE, Fraction.TWO, Fraction.ZERO);
181         checkReference("kg/m/s²",
182                        1.0,
183                        Fraction.ONE, Fraction.MINUS_ONE, new Fraction(-2), Fraction.ZERO);
184     }
185 
186     @Test
187     public void testCcsdsRoot() {
188         checkReference("km**0.5/s",
189                        FastMath.sqrt(1000.0),
190                        Fraction.ZERO, Fraction.ONE_HALF, Fraction.MINUS_ONE, Fraction.ZERO);
191         checkReference("km/s**0.5",
192                        1000.0,
193                        Fraction.ZERO, Fraction.ONE, new Fraction(-1, 2), Fraction.ZERO);
194     }
195 
196     @Test
197     public void testNumber() {
198         checkReference("#/yr",
199                        1.0 / Constants.JULIAN_YEAR,
200                        Fraction.ZERO, Fraction.ZERO, Fraction.MINUS_ONE, Fraction.ZERO);
201     }
202 
203     @Test
204     public void testReciprocal() {
205         checkReference("1/s",
206                        1.0,
207                        Fraction.ZERO, Fraction.ZERO, Fraction.MINUS_ONE, Fraction.ZERO);
208     }
209 
210     @Test
211     public void testSeveralMicro() {
212         checkReference("µs", // here we use U+00B5, MICRO SIGN
213                        1.0e-6,
214                        Fraction.ZERO, Fraction.ZERO, Fraction.ONE, Fraction.ZERO);
215         checkReference("μs", // here we use U+03BC, GREEK SMALL LETTER MU
216                        1.0e-6,
217                        Fraction.ZERO, Fraction.ZERO, Fraction.ONE, Fraction.ZERO);
218     }
219 
220     @Test
221     public void testEmpty() {
222         expectFailure("");
223     }
224 
225     @Test
226     public void testIncompleteExponent1() {
227         expectFailure("m.g^(2/)");
228     }
229 
230     @Test
231     public void testIncompleteExponent2() {
232         expectFailure("m.g^(2m)");
233     }
234 
235     @Test
236     public void testMissingClosingParenthesis() {
237         expectFailure("m.(W");
238     }
239 
240     @Test
241     public void testGarbageOnInput() {
242         expectFailure("kg+s");
243     }
244 
245     @Test
246     public void testFactor() {
247         checkReference("kg/3s",
248                        1.0 / 3.0,
249                        Fraction.ONE, Fraction.ZERO, Fraction.MINUS_ONE, Fraction.ZERO);
250     }
251 
252     @Test
253     public void testMissingUnit() {
254         expectFailure("km/√");
255     }
256 
257     @Test
258     public void testRootAndPower() {
259         expectFailure("km/√d³");
260     }
261 
262     @Test
263     public void testRootAndParenthesisedPower() {
264         checkReference("km/√(d³)",
265                        1000.0 / (Constants.JULIAN_DAY * FastMath.sqrt(Constants.JULIAN_DAY)),
266                        Fraction.ZERO, Fraction.ONE, new Fraction(-3, 2), Fraction.ZERO);
267     }
268 
269     private void checkReference(final String unitSpecification, final double scale,
270                                 final Fraction mass, final Fraction length,
271                                 final Fraction time, final Fraction angle) {
272         final Unit unit = Unit.parse(unitSpecification);
273         Assert.assertEquals(unitSpecification, unit.toString());
274         Assert.assertEquals(scale,  unit.getScale(), 1.0e-10 * scale);
275         Assert.assertEquals(mass,   unit.getMass());
276         Assert.assertEquals(length, unit.getLength());
277         Assert.assertEquals(time,   unit.getTime());
278         Assert.assertEquals(angle,  unit.getAngle());
279     }
280 
281     private void expectFailure(final String unitSpecification) {
282         try {
283             Unit.parse(unitSpecification);
284             Assert.fail("an exception should have been thrown");
285         } catch (OrekitException oe) {
286             Assert.assertEquals(OrekitMessages.UNKNOWN_UNIT, oe.getSpecifier());
287             Assert.assertEquals(unitSpecification, oe.getParts()[0]);
288         }
289     }
290 
291 }