1   /* Copyright 2002-2025 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.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.Test;
21  import org.orekit.errors.OrekitException;
22  import org.orekit.errors.OrekitMessages;
23  
24  import java.util.List;
25  
26  /**
27   * Unit tests for {@link Parser}.
28   *
29   * @author Luc Maisonobe
30   */
31  public class ParserTest {
32  
33      @Test
34      public void testNotAUnit() {
35          Assertions.assertNull(Parser.buildTermsList("n/a"));
36      }
37  
38      @Test
39      public void testOne() {
40          final List<PowerTerm> terms = Parser.buildTermsList("1");
41          Assertions.assertEquals(1, terms.size());
42          checkTerm(terms.get(0), 1, "1", 1, 1);
43      }
44  
45      @Test
46      public void testOneCompositeMultiplication() {
47          final List<PowerTerm> terms = Parser.buildTermsList("1×2s");
48          Assertions.assertEquals(2, terms.size());
49          checkTerm(terms.get(0), 1, "1", 1, 1);
50          checkTerm(terms.get(1), 2, "s", 1, 1);
51      }
52  
53      @Test
54      public void testOneCompositeDivision() {
55          final List<PowerTerm> terms = Parser.buildTermsList("1/2s");
56          Assertions.assertEquals(2, terms.size());
57          checkTerm(terms.get(0), 1,   "1",  1, 1);
58          checkTerm(terms.get(1), 0.5, "s", -1, 1);
59      }
60  
61      @Test
62      public void testNumber() {
63          final List<PowerTerm> terms = Parser.buildTermsList("#/y");
64          Assertions.assertEquals(2, terms.size());
65          checkTerm(terms.get(0), 1,  "#", 1, 1);
66          checkTerm(terms.get(1), 1, "y", -1, 1);
67      }
68  
69      @Test
70      public void testIntegerPrefix() {
71          final List<PowerTerm> terms = Parser.buildTermsList("2rev/d²");
72          Assertions.assertEquals(2, terms.size());
73          checkTerm(terms.get(0), 2, "rev", 1, 1);
74          checkTerm(terms.get(1), 1,  "d", -2, 1);
75      }
76  
77      @Test
78      public void testSimpleFactor() {
79          final List<PowerTerm> terms = Parser.buildTermsList("kg/3s");
80          Assertions.assertEquals(2, terms.size());
81          checkTerm(terms.get(0), 1,          "kg", 1, 1);
82          checkTerm(terms.get(1), 1.0 / 3.0,  "s", -1, 1);
83      }
84  
85      @Test
86      public void testFinalFactor() {
87          final List<PowerTerm> terms = Parser.buildTermsList("kg/3");
88          Assertions.assertEquals(2, terms.size());
89          checkTerm(terms.get(0), 1,          "kg", 1, 1);
90          checkTerm(terms.get(1), 1.0 / 3.0,  "1", -1, 1);
91      }
92  
93      @Test
94      public void testCompositeFactor() {
95          final List<PowerTerm> terms = Parser.buildTermsList("3kg*N/5(s·2A)");
96          Assertions.assertEquals(4, terms.size());
97          checkTerm(terms.get(0), 3,          "kg", 1, 1);
98          checkTerm(terms.get(1), 1,          "N",  1, 1);
99          checkTerm(terms.get(2), 1.0 / 5.0,  "s", -1, 1);
100         checkTerm(terms.get(3), 1.0 / 2.0,  "A", -1, 1);
101     }
102 
103     @Test
104     public void testSquareRoot() {
105         final List<PowerTerm> terms = Parser.buildTermsList("abcd¹/1√ef");
106         Assertions.assertEquals(2, terms.size());
107         checkTerm(terms.get(0), 1, "abcd", 1, 1);
108         checkTerm(terms.get(1), 1, "ef", -1, 2);
109     }
110 
111     @Test
112     public void testChain() {
113         final List<PowerTerm> terms = Parser.buildTermsList("kg.m^(3/4)·s⁻¹");
114         Assertions.assertEquals(3, terms.size());
115         checkTerm(terms.get(0), 1, "kg", 1, 1);
116         checkTerm(terms.get(1), 1,  "m", 3, 4);
117         checkTerm(terms.get(2), 1, "s", -1, 1);
118     }
119 
120     @Test
121     public void testExponents() {
122         final List<PowerTerm> terms = Parser.buildTermsList("µas^⅖/(h**(2)×8m.√A)³");
123         Assertions.assertEquals(4, terms.size());
124         checkTerm(terms.get(0), 1,           "µas", 2, 5);
125         checkTerm(terms.get(1), 1,            "h", -6, 1);
126         checkTerm(terms.get(2), 1.0 / 512.0,  "m", -3, 1);
127         checkTerm(terms.get(3), 1,            "A", -3, 2);
128     }
129 
130     @Test
131     public void testCompoundInSquareRoot() {
132         final List<PowerTerm> terms = Parser.buildTermsList("km/√(kg.s)");
133         Assertions.assertEquals(3, terms.size());
134         checkTerm(terms.get(0), 1,  "km", 1, 1);
135         checkTerm(terms.get(1), 1, "kg", -1, 2);
136         checkTerm(terms.get(2), 1,  "s", -1, 2);
137     }
138 
139     @Test
140     public void testLeftAssociativity() {
141         final List<PowerTerm> terms1 = Parser.buildTermsList("(kg/m)/s²");
142         Assertions.assertEquals(3, terms1.size());
143         checkTerm(terms1.get(0), 1,  "kg", 1, 1);
144         checkTerm(terms1.get(1), 1,  "m", -1, 1);
145         checkTerm(terms1.get(2), 1,  "s", -2, 1);
146         final List<PowerTerm> terms2 = Parser.buildTermsList("kg/(m/s²)");
147         Assertions.assertEquals(3, terms2.size());
148         checkTerm(terms2.get(0), 1,  "kg", 1, 1);
149         checkTerm(terms2.get(1), 1,  "m", -1, 1);
150         checkTerm(terms2.get(2), 1,   "s", 2, 1);
151         final List<PowerTerm> terms3 = Parser.buildTermsList("kg/m/s²");
152         Assertions.assertEquals(3, terms3.size());
153         checkTerm(terms3.get(0), 1,  "kg", 1, 1);
154         checkTerm(terms3.get(1), 1,  "m", -1, 1);
155         checkTerm(terms3.get(2), 1,  "s", -2, 1);
156     }
157 
158     @Test
159     public void testCcsdsRoot() {
160         final List<PowerTerm> terms1 = Parser.buildTermsList("km**0.5/s");
161         Assertions.assertEquals(2, terms1.size());
162         checkTerm(terms1.get(0), 1,  "km", 1, 2);
163         checkTerm(terms1.get(1), 1,  "s", -1, 1);
164         final List<PowerTerm> terms2 = Parser.buildTermsList("km/s**0.5");
165         Assertions.assertEquals(2, terms2.size());
166         checkTerm(terms2.get(0), 1,  "km", 1, 1);
167         checkTerm(terms2.get(1), 1,  "s", -1, 2);
168     }
169 
170     @Test
171     public void testEmpty() {
172         expectFailure("");
173     }
174 
175     @Test
176     public void testIncompleteExponent1() {
177         expectFailure("m.g^(2/)");
178     }
179 
180     @Test
181     public void testIncompleteExponent2() {
182         expectFailure("m.g^(2m)");
183     }
184 
185     @Test
186     public void testMissingClosingParenthesis() {
187         expectFailure("m.(W");
188     }
189 
190     @Test
191     public void testGarbageOnInput() {
192         expectFailure("kg+s");
193     }
194 
195     @Test
196     public void testMissingUnit() {
197         expectFailure("km/√");
198     }
199 
200     @Test
201     public void testRootAndPower() {
202         expectFailure("km/√d³");
203     }
204 
205     @Test
206     public void testMissingTerm() {
207         expectFailure("m/2√");
208     }
209 
210     @Test
211     public void testRootAndParenthesisedPower() {
212         final List<PowerTerm> terms = Parser.buildTermsList("km/√(d³)");
213         Assertions.assertEquals(2, terms.size());
214         checkTerm(terms.get(0), 1,  "km", 1, 1);
215         checkTerm(terms.get(1), 1,  "d", -3, 2);
216     }
217 
218     private void checkTerm(final PowerTerm term, double scale, final String base, final int numerator, final int denominator) {
219         Assertions.assertEquals(scale,       term.getScale(), 1.0e-12);
220         Assertions.assertEquals(base,        term.getBase().toString());
221         Assertions.assertEquals(numerator,   term.getExponent().getNumerator());
222         Assertions.assertEquals(denominator, term.getExponent().getDenominator());
223     }
224 
225     private void expectFailure(final String unitSpecification) {
226         try {
227             Parser.buildTermsList(unitSpecification);
228             Assertions.fail("an exception should have been thrown");
229         } catch (OrekitException oe) {
230             Assertions.assertEquals(OrekitMessages.UNKNOWN_UNIT, oe.getSpecifier());
231             Assertions.assertEquals(unitSpecification, oe.getParts()[0]);
232         }
233     }
234 
235 }