blob: 7e74328a1982a17c8c32a0aae8d058fc79b5f40c [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 -080020import org.apache.commons.lang3.RandomUtils;
Carmelo Casconeb10194c2017-08-23 19:16:51 +020021import org.junit.Assert;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070022import org.junit.Rule;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070023import org.junit.Test;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070024import org.junit.rules.ExpectedException;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070025
26import java.nio.ByteBuffer;
27import java.nio.ByteOrder;
28import java.util.Random;
29
Carmelo Casconed047bd22017-08-29 21:36:07 +020030import static java.lang.Integer.max;
Carmelo Casconeb10194c2017-08-23 19:16:51 +020031import static java.lang.String.format;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070032import static org.hamcrest.MatcherAssert.assertThat;
33import static org.hamcrest.Matchers.equalTo;
34import static org.hamcrest.Matchers.is;
35
36public class ImmutableByteSequenceTest {
Carmelo Casconed047bd22017-08-29 21:36:07 +020037 public static final int MIN_RAND_FIT_VALUE = 0xf;
38 public static final int MAX_RAND_FIT_VALUE = 0x7fffffff;
Brian O'Connoraf1d12e2017-08-17 12:21:48 -070039 @Rule
40 public ExpectedException thrown = ExpectedException.none();
Carmelo Cascone6b32c992016-04-13 11:53:09 -070041
42 @Test
43 public void testCopy() throws Exception {
44
45 byte byteValue = (byte) 1;
Yuta HIGUCHI6800ced2017-11-20 11:15:37 -080046 short shortValue = byteValue;
47 int intValue = byteValue;
48 long longValue = byteValue;
Carmelo Cascone6b32c992016-04-13 11:53:09 -070049 byte[] arrayValue = new byte[64];
50 arrayValue[63] = byteValue;
51 ByteBuffer bufferValue = ByteBuffer.allocate(64).put(arrayValue);
52
53 ImmutableByteSequence bsByte = ImmutableByteSequence.copyFrom(byteValue);
54 ImmutableByteSequence bsShort = ImmutableByteSequence.copyFrom(shortValue);
55 ImmutableByteSequence bsInt = ImmutableByteSequence.copyFrom(intValue);
56 ImmutableByteSequence bsLong = ImmutableByteSequence.copyFrom(longValue);
57 ImmutableByteSequence bsArray = ImmutableByteSequence.copyFrom(arrayValue);
58 ImmutableByteSequence bsBuffer = ImmutableByteSequence.copyFrom(bufferValue);
59
60 assertThat("byte sequence of a byte value must have size 1",
61 bsByte.size(), is(equalTo(1)));
62 assertThat("byte sequence of a short value must have size 2",
63 bsShort.size(), is(equalTo(2)));
64 assertThat("byte sequence of an int value must have size 4",
65 bsInt.size(), is(equalTo(4)));
66 assertThat("byte sequence of a long value must have size 8",
67 bsLong.size(), is(equalTo(8)));
68 assertThat("byte sequence of a byte array value must have same size of the array",
69 bsArray.size(), is(equalTo(arrayValue.length)));
70 assertThat("byte sequence of a byte buffer value must have same size of the buffer",
71 bsBuffer.size(), is(equalTo(bufferValue.capacity())));
72
73 String errStr = "incorrect byte sequence value";
74
75 assertThat(errStr, bsByte.asArray()[0], is(equalTo(byteValue)));
76 assertThat(errStr, bsShort.asArray()[1], is(equalTo(byteValue)));
77 assertThat(errStr, bsInt.asArray()[3], is(equalTo(byteValue)));
78 assertThat(errStr, bsLong.asArray()[7], is(equalTo(byteValue)));
79 assertThat(errStr, bsArray.asArray()[63], is(equalTo(byteValue)));
80 assertThat(errStr, bsBuffer.asArray()[63], is(equalTo(byteValue)));
81 }
82
83 @Test
84 public void testEndianness() throws Exception {
85
Yuta HIGUCHI6800ced2017-11-20 11:15:37 -080086 long longValue = RandomUtils.nextLong();
Carmelo Cascone6b32c992016-04-13 11:53:09 -070087
88 // creates a new sequence from a big-endian buffer
89 ByteBuffer bbBigEndian = ByteBuffer
90 .allocate(8)
91 .order(ByteOrder.BIG_ENDIAN)
92 .putLong(longValue);
93 ImmutableByteSequence bsBufferCopyBigEndian =
94 ImmutableByteSequence.copyFrom(bbBigEndian);
95
96 // creates a new sequence from a little-endian buffer
97 ByteBuffer bbLittleEndian = ByteBuffer
98 .allocate(8)
99 .order(ByteOrder.LITTLE_ENDIAN)
100 .putLong(longValue);
101 ImmutableByteSequence bsBufferCopyLittleEndian =
102 ImmutableByteSequence.copyFrom(bbLittleEndian);
103
104 // creates a new sequence from primitive type
105 ImmutableByteSequence bsLongCopy =
106 ImmutableByteSequence.copyFrom(longValue);
107
108
109 new EqualsTester()
110 // big-endian byte array cannot be equal to little-endian array
111 .addEqualityGroup(bbBigEndian.array())
112 .addEqualityGroup(bbLittleEndian.array())
113 // all byte sequences must be equal
114 .addEqualityGroup(bsBufferCopyBigEndian,
115 bsBufferCopyLittleEndian,
116 bsLongCopy)
117 // byte buffer views of all sequences must be equal
118 .addEqualityGroup(bsBufferCopyBigEndian.asReadOnlyBuffer(),
119 bsBufferCopyLittleEndian.asReadOnlyBuffer(),
120 bsLongCopy.asReadOnlyBuffer())
121 // byte buffer orders of all sequences must be ByteOrder.BIG_ENDIAN
122 .addEqualityGroup(bsBufferCopyBigEndian.asReadOnlyBuffer().order(),
123 bsBufferCopyLittleEndian.asReadOnlyBuffer().order(),
124 bsLongCopy.asReadOnlyBuffer().order(),
125 ByteOrder.BIG_ENDIAN)
126 .testEquals();
127 }
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700128
129 @Test
130 public void testBitSetMethods() throws Exception {
131 // All zeros tests
132 assertThat("3 bytes, all 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200133 ImmutableByteSequence.ofZeros(3),
134 is(equalTo(ImmutableByteSequence.copyFrom(
135 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700136 assertThat("3 bytes, all 0's via prefix",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200137 ImmutableByteSequence.prefixZeros(3, 3 * Byte.SIZE),
138 is(equalTo(ImmutableByteSequence.copyFrom(
139 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700140
141 // All ones tests
142 assertThat("3 bytes, all 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200143 ImmutableByteSequence.ofZeros(3),
144 is(equalTo(ImmutableByteSequence.copyFrom(
145 new byte[]{0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700146 assertThat("3 bytes, all 1's via prefix",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200147 ImmutableByteSequence.prefixOnes(3, 3 * Byte.SIZE),
148 is(equalTo(ImmutableByteSequence.copyFrom(
149 new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700150
151 // Zero prefix tests
152 assertThat("2 bytes, prefixed with 5 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200153 ImmutableByteSequence.prefix(2, 5, (byte) 0),
154 is(equalTo(ImmutableByteSequence.copyFrom(
155 new byte[]{(byte) 0x7, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700156 assertThat("4 bytes, prefixed with 16 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200157 ImmutableByteSequence.prefix(4, 16, (byte) 0),
158 is(equalTo(ImmutableByteSequence.copyFrom(
159 new byte[]{0, 0, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700160 assertThat("4 bytes, prefixed with 20 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200161 ImmutableByteSequence.prefix(4, 20, (byte) 0),
162 is(equalTo(ImmutableByteSequence.copyFrom(
163 new byte[]{0, 0, (byte) 0x0f, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700164 assertThat("8 bytes, prefixed with 36 0's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200165 ImmutableByteSequence.prefixZeros(8, 38),
166 is(equalTo(ImmutableByteSequence.copyFrom(
167 new byte[]{0, 0, 0, 0, (byte) 0x03, (byte) 0xff, (byte) 0xff, (byte) 0xff}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700168
169 // Ones prefix tests
170 assertThat("2 bytes, prefixed with 5 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200171 ImmutableByteSequence.prefix(2, 5, (byte) 0xff),
172 is(equalTo(ImmutableByteSequence.copyFrom(
173 new byte[]{(byte) 0xf8, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700174 assertThat("4 bytes, prefixed with 16 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200175 ImmutableByteSequence.prefix(4, 16, (byte) 0xff),
176 is(equalTo(ImmutableByteSequence.copyFrom(
177 new byte[]{(byte) 0xff, (byte) 0xff, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700178 assertThat("4 bytes, prefixed with 20 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200179 ImmutableByteSequence.prefix(4, 20, (byte) 0xff),
180 is(equalTo(ImmutableByteSequence.copyFrom(
181 new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xf0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700182 assertThat("8 bytes, prefixed with 10 1's",
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200183 ImmutableByteSequence.prefixOnes(8, 10),
184 is(equalTo(ImmutableByteSequence.copyFrom(
185 new byte[]{(byte) 0xff, (byte) 0xc0, 0, 0, 0, 0, 0, 0}))));
Brian O'Connoraf1d12e2017-08-17 12:21:48 -0700186 }
187
188 @Test
189 public void testBadPrefixVal() {
190 thrown.expect(IllegalArgumentException.class);
191 thrown.reportMissingExceptionWithMessage(
192 "Expect IllegalArgumentException due to val = 0x7");
193 ImmutableByteSequence.prefix(5, 10, (byte) 0x7);
194 }
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200195
196 @Test
197 public void testMsbIndex() {
198 assertThat("Value 0 should have MSB index -1",
199 ImmutableByteSequence.copyFrom(0).msbIndex(), is(-1));
200 for (int i = 0; i < 63; i++) {
201 long value = (long) Math.pow(2, i);
202 assertThat(format("Value %d should have MSB index %d", value, i),
203 ImmutableByteSequence.copyFrom(value).msbIndex(), is(i));
204 }
205 }
206
207 private void checkIllegalFit(ImmutableByteSequence bytes, int bitWidth) {
208 try {
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700209 bytes.fit(bitWidth);
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200210 Assert.fail(format("Except ByteSequenceTrimException due to value = %s and bitWidth %d",
211 bytes.toString(), bitWidth));
212 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
213 // We expect this.
214 }
215 }
216
217 private void checkLegalFit(ImmutableByteSequence bytes, int bitWidth)
218 throws ImmutableByteSequence.ByteSequenceTrimException {
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700219 ImmutableByteSequence fitBytes = bytes.fit(bitWidth);
220 ImmutableByteSequence sameBytes = fitBytes.fit(bytes.size() * 8);
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200221 assertThat(format("Fitted value %s (re-extended to %s) not equal to original value %s",
222 fitBytes, sameBytes, bytes),
223 sameBytes,
224 is(equalTo(bytes)));
225 }
226
227 @Test
228 public void testFit() throws ImmutableByteSequence.ByteSequenceTrimException {
229 // Test fit by forcing a given MSB index.
230 for (int msbIndex = 0; msbIndex < 32; msbIndex++) {
231 long value = (long) Math.pow(2, msbIndex);
232 ImmutableByteSequence bytes = ImmutableByteSequence.copyFrom(value);
233 checkLegalFit(bytes, msbIndex + 1);
234 if (msbIndex != 0) {
235 checkIllegalFit(bytes, msbIndex);
236 }
237 }
238 }
239
240 @Test
241 public void testRandomFit() throws ImmutableByteSequence.ByteSequenceTrimException {
242 // Test fit against the computed MSB index.
243 Random random = new Random();
244 for (int i = 0; i < 1000; i++) {
Carmelo Casconed047bd22017-08-29 21:36:07 +0200245 int randValue = random.nextInt((MAX_RAND_FIT_VALUE - MIN_RAND_FIT_VALUE) + 1) + MIN_RAND_FIT_VALUE;
246 ImmutableByteSequence bytes = ImmutableByteSequence.copyFrom((long) randValue);
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200247 int msbIndex = bytes.msbIndex();
Carmelo Casconed047bd22017-08-29 21:36:07 +0200248 // Truncate.
249 checkIllegalFit(bytes, max(msbIndex - random.nextInt(16), 1));
250 // Expand.
251 checkLegalFit(bytes, msbIndex + 2 + random.nextInt(128));
252 // Fit to same bit-width of original value.
Carmelo Casconeb10194c2017-08-23 19:16:51 +0200253 checkLegalFit(bytes, msbIndex + 1);
254 }
255 }
Carmelo Cascone8a571af2018-04-06 23:17:04 -0700256
257 @Test
258 public void testBitwiseOperations() {
259 Random random = new Random();
260 long long1 = random.nextLong();
261 long long2 = random.nextLong();
262
263 ImmutableByteSequence bs1 = ImmutableByteSequence.copyFrom(long1);
264 ImmutableByteSequence bs2 = ImmutableByteSequence.copyFrom(long2);
265
266 ImmutableByteSequence andBs = bs1.bitwiseAnd(bs2);
267 ImmutableByteSequence orBs = bs1.bitwiseOr(bs2);
268 ImmutableByteSequence xorBs = bs1.bitwiseXor(bs2);
269
270 assertThat("Invalid bitwise AND result",
271 andBs.asReadOnlyBuffer().getLong(), is(long1 & long2));
272 assertThat("Invalid bitwise OR result",
273 orBs.asReadOnlyBuffer().getLong(), is(long1 | long2));
274 assertThat("Invalid bitwise XOR result",
275 xorBs.asReadOnlyBuffer().getLong(), is(long1 ^ long2));
276 }
277}