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.gnss.metric.parser;
18  
19  import org.hipparchus.util.FastMath;
20  import org.junit.jupiter.api.Assertions;
21  import org.junit.jupiter.api.Test;
22  import org.orekit.errors.OrekitException;
23  import org.orekit.errors.OrekitMessages;
24  
25  import java.util.Random;
26  
27  public abstract class AbstractEncodedMessageTest {
28  
29      protected abstract EncodedMessage buildRawMessages(byte[] bytes);
30  
31      private EncodedMessage buildAndStart(byte[] bytes) {
32          final EncodedMessage m = buildRawMessages(bytes);
33          m.start();
34          return m;
35      }
36  
37      @Test
38      public void testTooLargeDataType() {
39          try {
40              buildAndStart(new byte[] { 0, 1, 2, 3, 4, 5}).extractBits(64);
41              Assertions.fail("an exception should habe been thrown");
42          } catch (OrekitException re) {
43              Assertions.assertEquals(OrekitMessages.TOO_LARGE_DATA_TYPE, re.getSpecifier());
44              Assertions.assertEquals(64, ((Integer) re.getParts()[0]).intValue());
45          }
46      }
47  
48      @Test
49      public void testUnexpectedNoData() {
50          try {
51              buildAndStart(new byte[0]).extractBits(1);
52              Assertions.fail("an exception should habe been thrown");
53          } catch (OrekitException re) {
54              Assertions.assertEquals(OrekitMessages.END_OF_ENCODED_MESSAGE, re.getSpecifier());
55          }
56      }
57  
58      @Test
59      public void testZeroBits() {
60          Assertions.assertEquals(0, buildAndStart(new byte[0]).extractBits(0));
61      }
62  
63      @Test
64      public void testFirstByte() {
65          final String s = "11111111";
66          Assertions.assertEquals(0x01, buildAndStart(byteArrayFromBinary(s)).extractBits(1));
67          Assertions.assertEquals(0x03, buildAndStart(byteArrayFromBinary(s)).extractBits(2));
68          Assertions.assertEquals(0x07, buildAndStart(byteArrayFromBinary(s)).extractBits(3));
69          Assertions.assertEquals(0x0F, buildAndStart(byteArrayFromBinary(s)).extractBits(4));
70          Assertions.assertEquals(0x1F, buildAndStart(byteArrayFromBinary(s)).extractBits(5));
71          Assertions.assertEquals(0x3F, buildAndStart(byteArrayFromBinary(s)).extractBits(6));
72          Assertions.assertEquals(0x7F, buildAndStart(byteArrayFromBinary(s)).extractBits(7));
73          Assertions.assertEquals(0xFF, buildAndStart(byteArrayFromBinary(s)).extractBits(8));
74      }
75  
76      @Test
77      public void testExhaustAfterInitialSuccess() {
78          EncodedMessage m = buildAndStart(byteArrayFromBinary("10111011"));
79          Assertions.assertEquals(5, m.extractBits(3));
80          Assertions.assertEquals(3, m.extractBits(2));
81          try {
82              m.extractBits(4);
83              Assertions.fail("an exception should habe been thrown");
84          } catch (OrekitException re) {
85              Assertions.assertEquals(OrekitMessages.END_OF_ENCODED_MESSAGE, re.getSpecifier());
86          }
87      }
88  
89      @Test
90      public void testCrossingByte() {
91          EncodedMessage m = buildAndStart(byteArrayFromBinary("0100110101101011"));
92          Assertions.assertEquals(0x09, m.extractBits(5));
93          Assertions.assertEquals(0x2B, m.extractBits(6));
94          Assertions.assertEquals(0x0B, m.extractBits(5));
95      }
96  
97      @Test
98      public void testLargeType() {
99          EncodedMessage m = buildAndStart(byteArrayFromBinary("01001101011010110100110101101011"));
100         Assertions.assertEquals(0x4D6B4D6B, m.extractBits(32));
101     }
102 
103     @Test
104     public void testRandom() {
105         Random random = new Random(0x9454c64b36d9b1b1l);
106         for (int i = 0; i < 1000; ++i) {
107 
108             // generate a random byte array, and the corresponding bits array
109             int nbBytes = 1 + random.nextInt(2000);
110             byte[] bits = new byte[nbBytes * 8];
111             for (int k = 0; k < bits.length; ++k) {
112                 bits[k] = (byte) (random.nextBoolean() ? 1 : 0);
113             }
114             byte[] array = new byte[nbBytes];
115             for (int k = 0; k < array.length; ++k) {
116                 array[k] = (byte) ((bits[8 * k    ] << 7) |
117                                    (bits[8 * k + 1] << 6) |
118                                    (bits[8 * k + 2] << 5) |
119                                    (bits[8 * k + 3] << 4) |
120                                    (bits[8 * k + 4] << 3) |
121                                    (bits[8 * k + 5] << 2) |
122                                    (bits[8 * k + 6] << 1) |
123                                    (bits[8 * k + 7]));
124             }
125 
126             EncodedMessage m = buildAndStart(array);
127 
128             int index = 0;
129             int size  = 0;
130             for (int remaining = bits.length; remaining > 0; remaining -= size) {
131                 size = FastMath.min(remaining, 1 + random.nextInt(63));
132                 long ref = 0l;
133                 for (int k = 0; k < size; ++k) {
134                     ref = (ref << 1) | bits[index++];
135                 }
136                 Assertions.assertEquals(ref, m.extractBits(size));
137             }
138             try {
139                 m.extractBits(1);
140                 Assertions.fail("an exception should have been thrown");
141             } catch (OrekitException me) {
142                 Assertions.assertEquals(OrekitMessages.END_OF_ENCODED_MESSAGE, me.getSpecifier());
143             }
144 
145         }
146 
147     }
148 
149     private byte[] byteArrayFromBinary(String radix2Value) {
150         final byte[] array = new byte[radix2Value.length() / 8];
151         for (int i = 0; i < array.length; ++i) {
152             for (int j = 0; j < 8; ++j) {
153                 if (radix2Value.charAt(8 * i + j) != '0') {
154                     array[i] |= 0x1 << (7 - j);
155                 }
156             }
157         }
158         return array;
159     }
160 
161 }