blob: 76981e8c41f60fbb753f9d113bd654eeb461e83f [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;
Yuta HIGUCHI6800ced2017-11-20 11:15:37 -080020
21import org.apache.commons.lang3.RandomUtils;
Carmelo Casconeb10194c2017-08-23 19:16:51 +020022import org.junit.Assert;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070023import org.junit.Rule;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070024import org.junit.Test;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070025import org.junit.rules.ExpectedException;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070026
27import java.nio.ByteBuffer;
28import java.nio.ByteOrder;
29import java.util.Random;
30
Carmelo Casconed047bd22017-08-29 21:36:07 +020031import static java.lang.Integer.max;
Carmelo Casconeb10194c2017-08-23 19:16:51 +020032import static java.lang.String.format;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070033import static org.hamcrest.MatcherAssert.assertThat;
34import static org.hamcrest.Matchers.equalTo;
35import static org.hamcrest.Matchers.is;
36
37public class ImmutableByteSequenceTest {
Carmelo Casconed047bd22017-08-29 21:36:07 +020038 public static final int MIN_RAND_FIT_VALUE = 0xf;
39 public static final int MAX_RAND_FIT_VALUE = 0x7fffffff;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070040 @Rule
41 public ExpectedException thrown = ExpectedException.none();
Carmelo Cascone6b32c992016-04-13 11:53:09 -070042
43 @Test
44 public void testCopy() throws Exception {
45
46 byte byteValue = (byte) 1;
Yuta HIGUCHI6800ced2017-11-20 11:15:37 -080047 short shortValue = byteValue;
48 int intValue = byteValue;
49 long longValue = byteValue;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070050 byte[] arrayValue = new byte[64];
51 arrayValue[63] = byteValue;
52 ByteBuffer bufferValue = ByteBuffer.allocate(64).put(arrayValue);
53
54 ImmutableByteSequence bsByte = ImmutableByteSequence.copyFrom(byteValue);
55 ImmutableByteSequence bsShort = ImmutableByteSequence.copyFrom(shortValue);
56 ImmutableByteSequence bsInt = ImmutableByteSequence.copyFrom(intValue);
57 ImmutableByteSequence bsLong = ImmutableByteSequence.copyFrom(longValue);
58 ImmutableByteSequence bsArray = ImmutableByteSequence.copyFrom(arrayValue);
59 ImmutableByteSequence bsBuffer = ImmutableByteSequence.copyFrom(bufferValue);
60
61 assertThat("byte sequence of a byte value must have size 1",
62 bsByte.size(), is(equalTo(1)));
63 assertThat("byte sequence of a short value must have size 2",
64 bsShort.size(), is(equalTo(2)));
65 assertThat("byte sequence of an int value must have size 4",
66 bsInt.size(), is(equalTo(4)));
67 assertThat("byte sequence of a long value must have size 8",
68 bsLong.size(), is(equalTo(8)));
69 assertThat("byte sequence of a byte array value must have same size of the array",
70 bsArray.size(), is(equalTo(arrayValue.length)));
71 assertThat("byte sequence of a byte buffer value must have same size of the buffer",
72 bsBuffer.size(), is(equalTo(bufferValue.capacity())));
73
74 String errStr = "incorrect byte sequence value";
75
76 assertThat(errStr, bsByte.asArray()[0], is(equalTo(byteValue)));
77 assertThat(errStr, bsShort.asArray()[1], is(equalTo(byteValue)));
78 assertThat(errStr, bsInt.asArray()[3], is(equalTo(byteValue)));
79 assertThat(errStr, bsLong.asArray()[7], is(equalTo(byteValue)));
80 assertThat(errStr, bsArray.asArray()[63], is(equalTo(byteValue)));
81 assertThat(errStr, bsBuffer.asArray()[63], is(equalTo(byteValue)));
82 }
83
84 @Test
85 public void testEndianness() throws Exception {
86
Yuta HIGUCHI6800ced2017-11-20 11:15:37 -080087 long longValue = RandomUtils.nextLong();
Carmelo Cascone6b32c992016-04-13 11:53:09 -070088
89 // creates a new sequence from a big-endian buffer
90 ByteBuffer bbBigEndian = ByteBuffer
91 .allocate(8)
92 .order(ByteOrder.BIG_ENDIAN)
93 .putLong(longValue);
94 ImmutableByteSequence bsBufferCopyBigEndian =
95 ImmutableByteSequence.copyFrom(bbBigEndian);
96
97 // creates a new sequence from a little-endian buffer
98 ByteBuffer bbLittleEndian = ByteBuffer
99 .allocate(8)
100 .order(ByteOrder.LITTLE_ENDIAN)
101 .putLong(longValue);
102 ImmutableByteSequence bsBufferCopyLittleEndian =
103 ImmutableByteSequence.copyFrom(bbLittleEndian);
104
105 // creates a new sequence from primitive type
106 ImmutableByteSequence bsLongCopy =
107 ImmutableByteSequence.copyFrom(longValue);
108
109
110 new EqualsTester()
111 // big-endian byte array cannot be equal to little-endian array
112 .addEqualityGroup(bbBigEndian.array())
113 .addEqualityGroup(bbLittleEndian.array())
114 // all byte sequences must be equal
115 .addEqualityGroup(bsBufferCopyBigEndian,
116 bsBufferCopyLittleEndian,
117 bsLongCopy)
118 // byte buffer views of all sequences must be equal
119 .addEqualityGroup(bsBufferCopyBigEndian.asReadOnlyBuffer(),
120 bsBufferCopyLittleEndian.asReadOnlyBuffer(),
121 bsLongCopy.asReadOnlyBuffer())
122 // byte buffer orders of all sequences must be ByteOrder.BIG_ENDIAN
123 .addEqualityGroup(bsBufferCopyBigEndian.asReadOnlyBuffer().order(),
124 bsBufferCopyLittleEndian.asReadOnlyBuffer().order(),
125 bsLongCopy.asReadOnlyBuffer().order(),
126 ByteOrder.BIG_ENDIAN)
127 .testEquals();
128 }
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700129
130 @Test
131 public void testBitSetMethods() throws Exception {
132 // All zeros tests
133 assertThat("3 bytes, all 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200134 ImmutableByteSequence.ofZeros(3),
135 is(equalTo(ImmutableByteSequence.copyFrom(
136 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700137 assertThat("3 bytes, all 0's via prefix",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200138 ImmutableByteSequence.prefixZeros(3, 3 * Byte.SIZE),
139 is(equalTo(ImmutableByteSequence.copyFrom(
140 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700141
142 // All ones tests
143 assertThat("3 bytes, all 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200144 ImmutableByteSequence.ofZeros(3),
145 is(equalTo(ImmutableByteSequence.copyFrom(
146 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700147 assertThat("3 bytes, all 1's via prefix",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200148 ImmutableByteSequence.prefixOnes(3, 3 * Byte.SIZE),
149 is(equalTo(ImmutableByteSequence.copyFrom(
150 new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700151
152 // Zero prefix tests
153 assertThat("2 bytes, prefixed with 5 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200154 ImmutableByteSequence.prefix(2, 5, (byte) 0),
155 is(equalTo(ImmutableByteSequence.copyFrom(
156 new byte[]{(byte) 0x7, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700157 assertThat("4 bytes, prefixed with 16 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200158 ImmutableByteSequence.prefix(4, 16, (byte) 0),
159 is(equalTo(ImmutableByteSequence.copyFrom(
160 new byte[]{0, 0, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700161 assertThat("4 bytes, prefixed with 20 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200162 ImmutableByteSequence.prefix(4, 20, (byte) 0),
163 is(equalTo(ImmutableByteSequence.copyFrom(
164 new byte[]{0, 0, (byte) 0x0f, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700165 assertThat("8 bytes, prefixed with 36 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200166 ImmutableByteSequence.prefixZeros(8, 38),
167 is(equalTo(ImmutableByteSequence.copyFrom(
168 new byte[]{0, 0, 0, 0, (byte) 0x03, (byte) 0xff, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700169
170 // Ones prefix tests
171 assertThat("2 bytes, prefixed with 5 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200172 ImmutableByteSequence.prefix(2, 5, (byte) 0xff),
173 is(equalTo(ImmutableByteSequence.copyFrom(
174 new byte[]{(byte) 0xf8, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700175 assertThat("4 bytes, prefixed with 16 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200176 ImmutableByteSequence.prefix(4, 16, (byte) 0xff),
177 is(equalTo(ImmutableByteSequence.copyFrom(
178 new byte[]{(byte) 0xff, (byte) 0xff, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700179 assertThat("4 bytes, prefixed with 20 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200180 ImmutableByteSequence.prefix(4, 20, (byte) 0xff),
181 is(equalTo(ImmutableByteSequence.copyFrom(
182 new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xf0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700183 assertThat("8 bytes, prefixed with 10 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200184 ImmutableByteSequence.prefixOnes(8, 10),
185 is(equalTo(ImmutableByteSequence.copyFrom(
186 new byte[]{(byte) 0xff, (byte) 0xc0, 0, 0, 0, 0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700187 }
188
189 @Test
190 public void testBadPrefixVal() {
191 thrown.expect(IllegalArgumentException.class);
192 thrown.reportMissingExceptionWithMessage(
193 "Expect IllegalArgumentException due to val = 0x7");
194 ImmutableByteSequence.prefix(5, 10, (byte) 0x7);
195 }
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200196
197 @Test
198 public void testMsbIndex() {
199 assertThat("Value 0 should have MSB index -1",
200 ImmutableByteSequence.copyFrom(0).msbIndex(), is(-1));
201 for (int i = 0; i < 63; i++) {
202 long value = (long) Math.pow(2, i);
203 assertThat(format("Value %d should have MSB index %d", value, i),
204 ImmutableByteSequence.copyFrom(value).msbIndex(), is(i));
205 }
206 }
207
208 private void checkIllegalFit(ImmutableByteSequence bytes, int bitWidth) {
209 try {
210 ImmutableByteSequence.fit(bytes, bitWidth);
211 Assert.fail(format("Except ByteSequenceTrimException due to value = %s and bitWidth %d",
212 bytes.toString(), bitWidth));
213 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
214 // We expect this.
215 }
216 }
217
218 private void checkLegalFit(ImmutableByteSequence bytes, int bitWidth)
219 throws ImmutableByteSequence.ByteSequenceTrimException {
220 ImmutableByteSequence fitBytes = ImmutableByteSequence.fit(bytes, bitWidth);
221 ImmutableByteSequence sameBytes = ImmutableByteSequence.fit(fitBytes, bytes.size() * 8);
222 assertThat(format("Fitted value %s (re-extended to %s) not equal to original value %s",
223 fitBytes, sameBytes, bytes),
224 sameBytes,
225 is(equalTo(bytes)));
226 }
227
228 @Test
229 public void testFit() throws ImmutableByteSequence.ByteSequenceTrimException {
230 // Test fit by forcing a given MSB index.
231 for (int msbIndex = 0; msbIndex < 32; msbIndex++) {
232 long value = (long) Math.pow(2, msbIndex);
233 ImmutableByteSequence bytes = ImmutableByteSequence.copyFrom(value);
234 checkLegalFit(bytes, msbIndex + 1);
235 if (msbIndex != 0) {
236 checkIllegalFit(bytes, msbIndex);
237 }
238 }
239 }
240
241 @Test
242 public void testRandomFit() throws ImmutableByteSequence.ByteSequenceTrimException {
243 // Test fit against the computed MSB index.
244 Random random = new Random();
245 for (int i = 0; i < 1000; i++) {
Carmelo Casconed047bd22017-08-29 21:36:07 +0200246 int randValue = random.nextInt((MAX_RAND_FIT_VALUE - MIN_RAND_FIT_VALUE) + 1) + MIN_RAND_FIT_VALUE;
247 ImmutableByteSequence bytes = ImmutableByteSequence.copyFrom((long) randValue);
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200248 int msbIndex = bytes.msbIndex();
Carmelo Casconed047bd22017-08-29 21:36:07 +0200249 // Truncate.
250 checkIllegalFit(bytes, max(msbIndex - random.nextInt(16), 1));
251 // Expand.
252 checkLegalFit(bytes, msbIndex + 2 + random.nextInt(128));
253 // Fit to same bit-width of original value.
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200254 checkLegalFit(bytes, msbIndex + 1);
255 }
256 }
Carmelo Cascone6b32c992016-04-13 11:53:09 -0700257}