blob: e15065e52553adc7e92384b0bc08e1abed0c7c6f [file] [log] [blame]
Carmelo Cascone6b32c992016-04-13 11:53:09 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Carmelo Cascone6b32c992016-04-13 11:53:09 -07003 *
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
17package org.onlab.util;
18
19import com.google.common.testing.EqualsTester;
Carmelo Casconeb10194c2017-08-23 19:16:51 +020020import org.junit.Assert;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070021import org.junit.Rule;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070022import org.junit.Test;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070023import org.junit.rules.ExpectedException;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070024
25import java.nio.ByteBuffer;
26import java.nio.ByteOrder;
27import java.util.Random;
28
Carmelo Casconed047bd22017-08-29 21:36:07 +020029import static java.lang.Integer.max;
Carmelo Casconeb10194c2017-08-23 19:16:51 +020030import static java.lang.String.format;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070031import static org.hamcrest.MatcherAssert.assertThat;
32import static org.hamcrest.Matchers.equalTo;
33import static org.hamcrest.Matchers.is;
34
35public class ImmutableByteSequenceTest {
Carmelo Casconed047bd22017-08-29 21:36:07 +020036 public static final int MIN_RAND_FIT_VALUE = 0xf;
37 public static final int MAX_RAND_FIT_VALUE = 0x7fffffff;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070038 @Rule
39 public ExpectedException thrown = ExpectedException.none();
Carmelo Cascone6b32c992016-04-13 11:53:09 -070040
41 @Test
42 public void testCopy() throws Exception {
43
44 byte byteValue = (byte) 1;
45 short shortValue = (short) byteValue;
46 int intValue = (int) byteValue;
47 long longValue = (long) byteValue;
48 byte[] arrayValue = new byte[64];
49 arrayValue[63] = byteValue;
50 ByteBuffer bufferValue = ByteBuffer.allocate(64).put(arrayValue);
51
52 ImmutableByteSequence bsByte = ImmutableByteSequence.copyFrom(byteValue);
53 ImmutableByteSequence bsShort = ImmutableByteSequence.copyFrom(shortValue);
54 ImmutableByteSequence bsInt = ImmutableByteSequence.copyFrom(intValue);
55 ImmutableByteSequence bsLong = ImmutableByteSequence.copyFrom(longValue);
56 ImmutableByteSequence bsArray = ImmutableByteSequence.copyFrom(arrayValue);
57 ImmutableByteSequence bsBuffer = ImmutableByteSequence.copyFrom(bufferValue);
58
59 assertThat("byte sequence of a byte value must have size 1",
60 bsByte.size(), is(equalTo(1)));
61 assertThat("byte sequence of a short value must have size 2",
62 bsShort.size(), is(equalTo(2)));
63 assertThat("byte sequence of an int value must have size 4",
64 bsInt.size(), is(equalTo(4)));
65 assertThat("byte sequence of a long value must have size 8",
66 bsLong.size(), is(equalTo(8)));
67 assertThat("byte sequence of a byte array value must have same size of the array",
68 bsArray.size(), is(equalTo(arrayValue.length)));
69 assertThat("byte sequence of a byte buffer value must have same size of the buffer",
70 bsBuffer.size(), is(equalTo(bufferValue.capacity())));
71
72 String errStr = "incorrect byte sequence value";
73
74 assertThat(errStr, bsByte.asArray()[0], is(equalTo(byteValue)));
75 assertThat(errStr, bsShort.asArray()[1], is(equalTo(byteValue)));
76 assertThat(errStr, bsInt.asArray()[3], is(equalTo(byteValue)));
77 assertThat(errStr, bsLong.asArray()[7], is(equalTo(byteValue)));
78 assertThat(errStr, bsArray.asArray()[63], is(equalTo(byteValue)));
79 assertThat(errStr, bsBuffer.asArray()[63], is(equalTo(byteValue)));
80 }
81
82 @Test
83 public void testEndianness() throws Exception {
84
85 long longValue = new Random().nextLong();
86
87 // creates a new sequence from a big-endian buffer
88 ByteBuffer bbBigEndian = ByteBuffer
89 .allocate(8)
90 .order(ByteOrder.BIG_ENDIAN)
91 .putLong(longValue);
92 ImmutableByteSequence bsBufferCopyBigEndian =
93 ImmutableByteSequence.copyFrom(bbBigEndian);
94
95 // creates a new sequence from a little-endian buffer
96 ByteBuffer bbLittleEndian = ByteBuffer
97 .allocate(8)
98 .order(ByteOrder.LITTLE_ENDIAN)
99 .putLong(longValue);
100 ImmutableByteSequence bsBufferCopyLittleEndian =
101 ImmutableByteSequence.copyFrom(bbLittleEndian);
102
103 // creates a new sequence from primitive type
104 ImmutableByteSequence bsLongCopy =
105 ImmutableByteSequence.copyFrom(longValue);
106
107
108 new EqualsTester()
109 // big-endian byte array cannot be equal to little-endian array
110 .addEqualityGroup(bbBigEndian.array())
111 .addEqualityGroup(bbLittleEndian.array())
112 // all byte sequences must be equal
113 .addEqualityGroup(bsBufferCopyBigEndian,
114 bsBufferCopyLittleEndian,
115 bsLongCopy)
116 // byte buffer views of all sequences must be equal
117 .addEqualityGroup(bsBufferCopyBigEndian.asReadOnlyBuffer(),
118 bsBufferCopyLittleEndian.asReadOnlyBuffer(),
119 bsLongCopy.asReadOnlyBuffer())
120 // byte buffer orders of all sequences must be ByteOrder.BIG_ENDIAN
121 .addEqualityGroup(bsBufferCopyBigEndian.asReadOnlyBuffer().order(),
122 bsBufferCopyLittleEndian.asReadOnlyBuffer().order(),
123 bsLongCopy.asReadOnlyBuffer().order(),
124 ByteOrder.BIG_ENDIAN)
125 .testEquals();
126 }
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700127
128 @Test
129 public void testBitSetMethods() throws Exception {
130 // All zeros tests
131 assertThat("3 bytes, all 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200132 ImmutableByteSequence.ofZeros(3),
133 is(equalTo(ImmutableByteSequence.copyFrom(
134 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700135 assertThat("3 bytes, all 0's via prefix",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200136 ImmutableByteSequence.prefixZeros(3, 3 * Byte.SIZE),
137 is(equalTo(ImmutableByteSequence.copyFrom(
138 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700139
140 // All ones tests
141 assertThat("3 bytes, all 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200142 ImmutableByteSequence.ofZeros(3),
143 is(equalTo(ImmutableByteSequence.copyFrom(
144 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700145 assertThat("3 bytes, all 1's via prefix",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200146 ImmutableByteSequence.prefixOnes(3, 3 * Byte.SIZE),
147 is(equalTo(ImmutableByteSequence.copyFrom(
148 new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700149
150 // Zero prefix tests
151 assertThat("2 bytes, prefixed with 5 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200152 ImmutableByteSequence.prefix(2, 5, (byte) 0),
153 is(equalTo(ImmutableByteSequence.copyFrom(
154 new byte[]{(byte) 0x7, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700155 assertThat("4 bytes, prefixed with 16 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200156 ImmutableByteSequence.prefix(4, 16, (byte) 0),
157 is(equalTo(ImmutableByteSequence.copyFrom(
158 new byte[]{0, 0, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700159 assertThat("4 bytes, prefixed with 20 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200160 ImmutableByteSequence.prefix(4, 20, (byte) 0),
161 is(equalTo(ImmutableByteSequence.copyFrom(
162 new byte[]{0, 0, (byte) 0x0f, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700163 assertThat("8 bytes, prefixed with 36 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200164 ImmutableByteSequence.prefixZeros(8, 38),
165 is(equalTo(ImmutableByteSequence.copyFrom(
166 new byte[]{0, 0, 0, 0, (byte) 0x03, (byte) 0xff, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700167
168 // Ones prefix tests
169 assertThat("2 bytes, prefixed with 5 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200170 ImmutableByteSequence.prefix(2, 5, (byte) 0xff),
171 is(equalTo(ImmutableByteSequence.copyFrom(
172 new byte[]{(byte) 0xf8, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700173 assertThat("4 bytes, prefixed with 16 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200174 ImmutableByteSequence.prefix(4, 16, (byte) 0xff),
175 is(equalTo(ImmutableByteSequence.copyFrom(
176 new byte[]{(byte) 0xff, (byte) 0xff, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700177 assertThat("4 bytes, prefixed with 20 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200178 ImmutableByteSequence.prefix(4, 20, (byte) 0xff),
179 is(equalTo(ImmutableByteSequence.copyFrom(
180 new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xf0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700181 assertThat("8 bytes, prefixed with 10 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200182 ImmutableByteSequence.prefixOnes(8, 10),
183 is(equalTo(ImmutableByteSequence.copyFrom(
184 new byte[]{(byte) 0xff, (byte) 0xc0, 0, 0, 0, 0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700185 }
186
187 @Test
188 public void testBadPrefixVal() {
189 thrown.expect(IllegalArgumentException.class);
190 thrown.reportMissingExceptionWithMessage(
191 "Expect IllegalArgumentException due to val = 0x7");
192 ImmutableByteSequence.prefix(5, 10, (byte) 0x7);
193 }
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200194
195 @Test
196 public void testMsbIndex() {
197 assertThat("Value 0 should have MSB index -1",
198 ImmutableByteSequence.copyFrom(0).msbIndex(), is(-1));
199 for (int i = 0; i < 63; i++) {
200 long value = (long) Math.pow(2, i);
201 assertThat(format("Value %d should have MSB index %d", value, i),
202 ImmutableByteSequence.copyFrom(value).msbIndex(), is(i));
203 }
204 }
205
206 private void checkIllegalFit(ImmutableByteSequence bytes, int bitWidth) {
207 try {
208 ImmutableByteSequence.fit(bytes, bitWidth);
209 Assert.fail(format("Except ByteSequenceTrimException due to value = %s and bitWidth %d",
210 bytes.toString(), bitWidth));
211 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
212 // We expect this.
213 }
214 }
215
216 private void checkLegalFit(ImmutableByteSequence bytes, int bitWidth)
217 throws ImmutableByteSequence.ByteSequenceTrimException {
218 ImmutableByteSequence fitBytes = ImmutableByteSequence.fit(bytes, bitWidth);
219 ImmutableByteSequence sameBytes = ImmutableByteSequence.fit(fitBytes, bytes.size() * 8);
220 assertThat(format("Fitted value %s (re-extended to %s) not equal to original value %s",
221 fitBytes, sameBytes, bytes),
222 sameBytes,
223 is(equalTo(bytes)));
224 }
225
226 @Test
227 public void testFit() throws ImmutableByteSequence.ByteSequenceTrimException {
228 // Test fit by forcing a given MSB index.
229 for (int msbIndex = 0; msbIndex < 32; msbIndex++) {
230 long value = (long) Math.pow(2, msbIndex);
231 ImmutableByteSequence bytes = ImmutableByteSequence.copyFrom(value);
232 checkLegalFit(bytes, msbIndex + 1);
233 if (msbIndex != 0) {
234 checkIllegalFit(bytes, msbIndex);
235 }
236 }
237 }
238
239 @Test
240 public void testRandomFit() throws ImmutableByteSequence.ByteSequenceTrimException {
241 // Test fit against the computed MSB index.
242 Random random = new Random();
243 for (int i = 0; i < 1000; i++) {
Carmelo Casconed047bd22017-08-29 21:36:07 +0200244 int randValue = random.nextInt((MAX_RAND_FIT_VALUE - MIN_RAND_FIT_VALUE) + 1) + MIN_RAND_FIT_VALUE;
245 ImmutableByteSequence bytes = ImmutableByteSequence.copyFrom((long) randValue);
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200246 int msbIndex = bytes.msbIndex();
Carmelo Casconed047bd22017-08-29 21:36:07 +0200247 // Truncate.
248 checkIllegalFit(bytes, max(msbIndex - random.nextInt(16), 1));
249 // Expand.
250 checkLegalFit(bytes, msbIndex + 2 + random.nextInt(128));
251 // Fit to same bit-width of original value.
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200252 checkLegalFit(bytes, msbIndex + 1);
253 }
254 }
Carmelo Cascone6b32c992016-04-13 11:53:09 -0700255}