• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.exoplayer2.util;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static org.junit.Assert.assertThrows;
20 
21 import androidx.test.ext.junit.runners.AndroidJUnit4;
22 import com.google.android.exoplayer2.C;
23 import com.google.android.exoplayer2.testutil.TestUtil;
24 import java.nio.charset.Charset;
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 
28 /** Tests for {@link ParsableBitArray}. */
29 @RunWith(AndroidJUnit4.class)
30 public final class ParsableBitArrayTest {
31 
32   @Test
readAllBytes()33   public void readAllBytes() {
34     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F);
35     ParsableBitArray testArray = new ParsableBitArray(testData);
36     byte[] bytesRead = new byte[testData.length];
37 
38     testArray.readBytes(bytesRead, 0, testData.length);
39 
40     assertThat(bytesRead).isEqualTo(testData);
41     assertThat(testArray.getPosition()).isEqualTo(testData.length * 8);
42     assertThat(testArray.getBytePosition()).isEqualTo(testData.length);
43   }
44 
45   @Test
readBitInSameByte()46   public void readBitInSameByte() {
47     byte[] testData = TestUtil.createByteArray(0, 0b00110000);
48     ParsableBitArray testArray = new ParsableBitArray(testData);
49     testArray.setPosition(10);
50 
51     assertThat(testArray.readBit()).isTrue();
52     assertThat(testArray.readBit()).isTrue();
53     assertThat(testArray.readBit()).isFalse();
54     assertThat(testArray.readBit()).isFalse();
55   }
56 
57   @Test
readBitInMultipleBytes()58   public void readBitInMultipleBytes() {
59     byte[] testData = TestUtil.createByteArray(1, 1 << 7);
60     ParsableBitArray testArray = new ParsableBitArray(testData);
61     testArray.setPosition(6);
62 
63     assertThat(testArray.readBit()).isFalse();
64     assertThat(testArray.readBit()).isTrue();
65     assertThat(testArray.readBit()).isTrue();
66     assertThat(testArray.readBit()).isFalse();
67   }
68 
69   @Test
readBits0Bits()70   public void readBits0Bits() {
71     byte[] testData = TestUtil.createByteArray(0x3C);
72     ParsableBitArray testArray = new ParsableBitArray(testData);
73 
74     int result = testArray.readBits(0);
75 
76     assertThat(result).isEqualTo(0);
77   }
78 
79   @Test
readBitsByteAligned()80   public void readBitsByteAligned() {
81     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
82     ParsableBitArray testArray = new ParsableBitArray(testData);
83     testArray.readBits(8);
84 
85     int result = testArray.readBits(18);
86 
87     assertThat(result).isEqualTo(0xD25F << 2);
88     assertThat(testArray.getPosition()).isEqualTo(26);
89   }
90 
91   @Test
readBitsNonByteAligned()92   public void readBitsNonByteAligned() {
93     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F);
94     ParsableBitArray testArray = new ParsableBitArray(testData);
95     testArray.readBits(3);
96 
97     int result = testArray.readBits(14);
98 
99     assertThat(result).isEqualTo((0x3C & 0b11111) << 9 | 0xD2 << 1 | 0x5F >> 7);
100     assertThat(testArray.getPosition()).isEqualTo(17);
101   }
102 
103   @Test
readBitsNegativeValue()104   public void readBitsNegativeValue() {
105     byte[] testData = TestUtil.createByteArray(0xF0, 0, 0, 0);
106     ParsableBitArray testArray = new ParsableBitArray(testData);
107 
108     int result = testArray.readBits(32);
109 
110     assertThat(result).isEqualTo(0xF0000000);
111   }
112 
113   @Test
readBitsToLong0Bits()114   public void readBitsToLong0Bits() {
115     byte[] testData = TestUtil.createByteArray(0x3C);
116     ParsableBitArray testArray = new ParsableBitArray(testData);
117 
118     long result = testArray.readBitsToLong(0);
119 
120     assertThat(result).isEqualTo(0);
121   }
122 
123   @Test
readBitsToLongByteAligned()124   public void readBitsToLongByteAligned() {
125     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01, 0xFF, 0x14, 0x60);
126     ParsableBitArray testArray = new ParsableBitArray(testData);
127     testArray.readBits(8);
128 
129     long result = testArray.readBitsToLong(45);
130 
131     assertThat(result).isEqualTo(0xD25F01FF14L << 5 | 0x60 >> 3);
132     assertThat(testArray.getPosition()).isEqualTo(53);
133   }
134 
135   @Test
readBitsToLongNonByteAligned()136   public void readBitsToLongNonByteAligned() {
137     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01, 0xFF, 0x14, 0x60);
138     ParsableBitArray testArray = new ParsableBitArray(testData);
139     testArray.readBits(3);
140 
141     long result = testArray.readBitsToLong(53);
142 
143     assertThat(result).isEqualTo((0x3CL & 0b11111) << 48 | 0xD25F01FF1460L);
144     assertThat(testArray.getPosition()).isEqualTo(56);
145   }
146 
147   @Test
readBitsToLongNegativeValue()148   public void readBitsToLongNegativeValue() {
149     byte[] testData = TestUtil.createByteArray(0xF0, 0, 0, 0, 0, 0, 0, 0);
150     ParsableBitArray testArray = new ParsableBitArray(testData);
151 
152     long result = testArray.readBitsToLong(64);
153 
154     assertThat(result).isEqualTo(0xF000000000000000L);
155   }
156 
157   @Test
readBitsToByteArray()158   public void readBitsToByteArray() {
159     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01, 0xFF, 0x14, 0x60, 0x99);
160     ParsableBitArray testArray = new ParsableBitArray(testData);
161 
162     int numBytes = testData.length;
163     byte[] result = new byte[numBytes];
164     // Test read within byte boundaries.
165     testArray.readBits(result, 0, 6);
166     assertThat(result[0]).isEqualTo((byte) (testData[0] & 0xFC));
167     // Test read across byte boundaries.
168     testArray.readBits(result, 0, 8);
169     assertThat(result[0])
170         .isEqualTo((byte) (((testData[0] & 0x03) << 6) | ((testData[1] & 0xFC) >> 2)));
171     // Test reading across multiple bytes.
172     testArray.readBits(result, 1, numBytes * 8 - 14);
173     for (int i = 1; i < numBytes - 1; i++) {
174       assertThat(result[i])
175           .isEqualTo((byte) (((testData[i] & 0x03) << 6) | ((testData[i + 1] & 0xFC) >> 2)));
176     }
177     assertThat(result[numBytes - 1]).isEqualTo((byte) ((testData[numBytes - 1] & 0x03) << 6));
178     assertThat(testArray.bitsLeft()).isEqualTo(0);
179     // Test read last buffer byte across input data bytes.
180     testArray.setPosition(31);
181     result[3] = 0;
182     testArray.readBits(result, 3, 3);
183     assertThat(result[3]).isEqualTo((byte) 0xE0);
184     // Test read bits in the middle of a input data byte.
185     result[0] = 0;
186     assertThat(testArray.getPosition()).isEqualTo(34);
187     testArray.readBits(result, 0, 3);
188     assertThat(result[0]).isEqualTo((byte) 0xE0);
189     // Test read 0 bits.
190     testArray.setPosition(32);
191     result[1] = 0;
192     testArray.readBits(result, 1, 0);
193     assertThat(result[1]).isEqualTo((byte) 0);
194     // Test reading a number of bits divisible by 8.
195     testArray.setPosition(0);
196     testArray.readBits(result, 0, 16);
197     assertThat(result[0]).isEqualTo(testData[0]);
198     assertThat(result[1]).isEqualTo(testData[1]);
199     // Test least significant bits are unmodified.
200     result[1] = (byte) 0xFF;
201     testArray.readBits(result, 0, 9);
202     assertThat(result[0]).isEqualTo((byte) 0x5F);
203     assertThat(result[1]).isEqualTo((byte) 0x7F);
204   }
205 
206   @Test
skipBytes()207   public void skipBytes() {
208     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
209     ParsableBitArray testArray = new ParsableBitArray(testData);
210 
211     testArray.skipBytes(2);
212 
213     assertThat(testArray.readBits(8)).isEqualTo(0x5F);
214   }
215 
216   @Test
skipBitsByteAligned()217   public void skipBitsByteAligned() {
218     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
219     ParsableBitArray testArray = new ParsableBitArray(testData);
220 
221     testArray.skipBits(16);
222 
223     assertThat(testArray.readBits(8)).isEqualTo(0x5F);
224   }
225 
226   @Test
skipBitsNonByteAligned()227   public void skipBitsNonByteAligned() {
228     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
229     ParsableBitArray testArray = new ParsableBitArray(testData);
230 
231     testArray.skipBits(5);
232 
233     assertThat(testArray.readBits(11)).isEqualTo((0x3C & 0b111) << 8 | 0xD2);
234   }
235 
236   @Test
setPositionByteAligned()237   public void setPositionByteAligned() {
238     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
239     ParsableBitArray testArray = new ParsableBitArray(testData);
240 
241     testArray.setPosition(16);
242 
243     assertThat(testArray.readBits(8)).isEqualTo(0x5F);
244   }
245 
246   @Test
setPositionNonByteAligned()247   public void setPositionNonByteAligned() {
248     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
249     ParsableBitArray testArray = new ParsableBitArray(testData);
250 
251     testArray.setPosition(5);
252 
253     assertThat(testArray.readBits(11)).isEqualTo((0x3C & 0b111) << 8 | 0xD2);
254   }
255 
256   @Test
byteAlignFromNonByteAligned()257   public void byteAlignFromNonByteAligned() {
258     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
259     ParsableBitArray testArray = new ParsableBitArray(testData);
260     testArray.setPosition(11);
261 
262     testArray.byteAlign();
263 
264     assertThat(testArray.getBytePosition()).isEqualTo(2);
265     assertThat(testArray.getPosition()).isEqualTo(16);
266     assertThat(testArray.readBits(8)).isEqualTo(0x5F);
267   }
268 
269   @Test
byteAlignFromByteAligned()270   public void byteAlignFromByteAligned() {
271     byte[] testData = TestUtil.createByteArray(0x3C, 0xD2, 0x5F, 0x01);
272     ParsableBitArray testArray = new ParsableBitArray(testData);
273     testArray.setPosition(16);
274 
275     testArray.byteAlign(); // Should be a no-op.
276 
277     assertThat(testArray.getBytePosition()).isEqualTo(2);
278     assertThat(testArray.getPosition()).isEqualTo(16);
279     assertThat(testArray.readBits(8)).isEqualTo(0x5F);
280   }
281 
282   @Test
readBytesAsStringDefaultsToUtf8()283   public void readBytesAsStringDefaultsToUtf8() {
284     byte[] testData = "a non-åscii strìng".getBytes(Charset.forName(C.UTF8_NAME));
285     ParsableBitArray testArray = new ParsableBitArray(testData);
286 
287     testArray.skipBytes(2);
288     assertThat(testArray.readBytesAsString(testData.length - 2)).isEqualTo("non-åscii strìng");
289   }
290 
291   @Test
readBytesAsStringExplicitCharset()292   public void readBytesAsStringExplicitCharset() {
293     byte[] testData = "a non-åscii strìng".getBytes(Charset.forName(C.UTF16_NAME));
294     ParsableBitArray testArray = new ParsableBitArray(testData);
295 
296     testArray.skipBytes(6);
297     assertThat(testArray.readBytesAsString(testData.length - 6, Charset.forName(C.UTF16_NAME)))
298         .isEqualTo("non-åscii strìng");
299   }
300 
301   @Test
readBytesNotByteAligned()302   public void readBytesNotByteAligned() {
303     String testString = "test string";
304     byte[] testData = testString.getBytes(Charset.forName(C.UTF8_NAME));
305     ParsableBitArray testArray = new ParsableBitArray(testData);
306 
307     testArray.skipBit();
308     assertThrows(IllegalStateException.class, () -> testArray.readBytesAsString(2));
309   }
310 
311   @Test
putBitsWithinByte()312   public void putBitsWithinByte() {
313     ParsableBitArray output = new ParsableBitArray(new byte[4]);
314     output.skipBits(1);
315 
316     output.putInt(0x3F, 5);
317 
318     output.setPosition(0);
319     assertThat(output.readBits(8)).isEqualTo(0x1F << 2); // Check that only 5 bits are modified.
320   }
321 
322   @Test
putBitsAcrossTwoBytes()323   public void putBitsAcrossTwoBytes() {
324     ParsableBitArray output = new ParsableBitArray(new byte[4]);
325     output.setPosition(12);
326 
327     output.putInt(0xFF, 8);
328 
329     output.setPosition(8);
330     assertThat(output.readBits(16)).isEqualTo(0x0FF0);
331   }
332 
333   @Test
putBitsAcrossMultipleBytes()334   public void putBitsAcrossMultipleBytes() {
335     ParsableBitArray output = new ParsableBitArray(new byte[8]);
336     output.setPosition(31); // Writing starts at 31 to test the 30th bit is not modified.
337 
338     output.putInt(0xFF146098, 30); // Write only 30 to test the 61st bit is not modified.
339 
340     output.setPosition(30);
341     assertThat(output.readBits(32)).isEqualTo(0x3F146098 << 1);
342   }
343 
344   @Test
put32Bits()345   public void put32Bits() {
346     ParsableBitArray output = new ParsableBitArray(new byte[5]);
347     output.setPosition(4);
348 
349     output.putInt(0xFF146098, 32);
350 
351     output.setPosition(4);
352     assertThat(output.readBits(32)).isEqualTo(0xFF146098);
353   }
354 
355   @Test
putFullBytes()356   public void putFullBytes() {
357     ParsableBitArray output = new ParsableBitArray(new byte[2]);
358 
359     output.putInt(0x81, 8);
360 
361     output.setPosition(0);
362     assertThat(output.readBits(8)).isEqualTo(0x81);
363   }
364 
365   @Test
noOverwriting()366   public void noOverwriting() {
367     ParsableBitArray output =
368         new ParsableBitArray(TestUtil.createByteArray(0xFF, 0xFF, 0xFF, 0xFF, 0xFF));
369     output.setPosition(1);
370 
371     output.putInt(0, 30);
372 
373     output.setPosition(0);
374     assertThat(output.readBits(32)).isEqualTo(0x80000001);
375   }
376 
377 }
378