• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package test.java.nio.Buffer;
24 
25 import org.testng.Assert;
26 import org.testng.annotations.DataProvider;
27 import org.testng.annotations.Test;
28 
29 import java.lang.invoke.MethodHandle;
30 import java.lang.invoke.MethodHandles;
31 import java.lang.invoke.MethodType;
32 import java.nio.Buffer;
33 import java.nio.ByteBuffer;
34 import java.nio.ByteOrder;
35 import java.nio.CharBuffer;
36 import java.nio.DoubleBuffer;
37 import java.nio.FloatBuffer;
38 import java.nio.IntBuffer;
39 import java.nio.LongBuffer;
40 import java.nio.ShortBuffer;
41 import java.util.HashMap;
42 import java.util.Map;
43 import java.util.function.BiFunction;
44 import java.util.function.LongFunction;
45 import java.util.stream.IntStream;
46 
47 /*
48  * @test
49  * @bug 8193085 8199773
50  * @summary tests for buffer equals and compare
51  * @run testng EqualsCompareTest
52  */
53 
54 public class EqualsCompareTest {
55 
56     // Maximum width in bits
57     static final int MAX_WIDTH = 512;
58 
59     static final Map<Class, Integer> typeToWidth;
60 
61     static {
62         typeToWidth = new HashMap<>();
typeToWidth.put(byte.class, Byte.SIZE)63         typeToWidth.put(byte.class, Byte.SIZE);
typeToWidth.put(short.class, Short.SIZE)64         typeToWidth.put(short.class, Short.SIZE);
typeToWidth.put(char.class, Character.SIZE)65         typeToWidth.put(char.class, Character.SIZE);
typeToWidth.put(int.class, Integer.SIZE)66         typeToWidth.put(int.class, Integer.SIZE);
typeToWidth.put(long.class, Long.SIZE)67         typeToWidth.put(long.class, Long.SIZE);
typeToWidth.put(float.class, Float.SIZE)68         typeToWidth.put(float.class, Float.SIZE);
typeToWidth.put(double.class, Double.SIZE)69         typeToWidth.put(double.class, Double.SIZE);
70     }
71 
arraySizeFor(Class<?> type)72     static int arraySizeFor(Class<?> type) {
73         assert type.isPrimitive();
74         return 4 * MAX_WIDTH / typeToWidth.get(type);
75     }
76 
77     enum BufferKind {
78         HEAP,
79         HEAP_VIEW,
80         DIRECT;
81     }
82 
83     static abstract class BufferType<T extends Buffer, E> {
84         final BufferKind k;
85         final Class<?> bufferType;
86         final Class<?> elementType;
87 
88         final MethodHandle eq;
89         final MethodHandle cmp;
90         final MethodHandle mismtch;
91 
92         final MethodHandle getter;
93         final MethodHandle setter;
94 
BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType)95         BufferType(BufferKind k, Class<T> bufferType, Class<?> elementType) {
96             this.k = k;
97             this.bufferType = bufferType;
98             this.elementType = elementType;
99 
100             var lookup = MethodHandles.lookup();
101             try {
102                 eq = lookup.findVirtual(bufferType, "equals", MethodType.methodType(boolean.class, Object.class));
103                 cmp = lookup.findVirtual(bufferType, "compareTo", MethodType.methodType(int.class, bufferType));
104                 mismtch = lookup.findVirtual(bufferType, "mismatch", MethodType.methodType(int.class, bufferType));
105 
106                 getter = lookup.findVirtual(bufferType, "get", MethodType.methodType(elementType, int.class));
107                 setter = lookup.findVirtual(bufferType, "put", MethodType.methodType(bufferType, int.class, elementType));
108             }
109             catch (Exception e) {
110                 throw new AssertionError(e);
111             }
112         }
113 
114         @Override
toString()115         public String toString() {
116             return bufferType.getName() + " " + k;
117         }
118 
construct(int length)119         T construct(int length) {
120             return construct(length, ByteOrder.BIG_ENDIAN);
121         }
122 
construct(int length, ByteOrder bo)123         abstract T construct(int length, ByteOrder bo);
124 
125         @SuppressWarnings("unchecked")
slice(T a, int from, int to, boolean dupOtherwiseSlice)126         T slice(T a, int from, int to, boolean dupOtherwiseSlice) {
127             a = (T) a.position(from).limit(to);
128             return (T) (dupOtherwiseSlice ? a.duplicate() : a.slice());
129         }
130 
131         @SuppressWarnings("unchecked")
get(T a, int i)132         E get(T a, int i) {
133             try {
134                 return (E) getter.invoke(a, i);
135             }
136             catch (RuntimeException | Error e) {
137                 throw e;
138             }
139             catch (Throwable t) {
140                 throw new Error(t);
141             }
142         }
143 
set(T a, int i, Object v)144         void set(T a, int i, Object v) {
145             try {
146                 setter.invoke(a, i, convert(v));
147             }
148             catch (RuntimeException | Error e) {
149                 throw e;
150             }
151             catch (Throwable t) {
152                 throw new Error(t);
153             }
154         }
155 
convert(Object o)156         abstract Object convert(Object o);
157 
equals(T a, T b)158         boolean equals(T a, T b) {
159             try {
160                 return (boolean) eq.invoke(a, b);
161             }
162             catch (RuntimeException | Error e) {
163                 throw e;
164             }
165             catch (Throwable t) {
166                 throw new Error(t);
167             }
168         }
169 
compare(T a, T b)170         int compare(T a, T b) {
171             try {
172                 return (int) cmp.invoke(a, b);
173             }
174             catch (RuntimeException | Error e) {
175                 throw e;
176             }
177             catch (Throwable t) {
178                 throw new Error(t);
179             }
180         }
181 
pairWiseEquals(T a, T b)182         boolean pairWiseEquals(T a, T b) {
183             if (a.remaining() != b.remaining())
184                 return false;
185             int p = a.position();
186             for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--)
187                 if (!get(a, i).equals(get(b, j)))
188                     return false;
189             return true;
190         }
191 
mismatch(T a, T b)192         int mismatch(T a, T b) {
193             try {
194                 return (int) mismtch.invoke(a, b);
195             }
196             catch (RuntimeException | Error e) {
197                 throw e;
198             }
199             catch (Throwable t) {
200                 throw new Error(t);
201             }
202         }
203 
204         static class Bytes extends BufferType<ByteBuffer, Byte> {
Bytes(BufferKind k)205             Bytes(BufferKind k) {
206                 super(k, ByteBuffer.class, byte.class);
207             }
208 
209             @Override
construct(int length, ByteOrder bo)210             ByteBuffer construct(int length, ByteOrder bo) {
211                 switch (k) {
212                     case DIRECT:
213                         return ByteBuffer.allocateDirect(length).order(bo);
214                     default:
215                     case HEAP_VIEW:
216                     case HEAP:
217                         return ByteBuffer.allocate(length).order(bo);
218                 }
219             }
220 
221             @Override
convert(Object o)222             Object convert(Object o) {
223                 return o instanceof Integer
224                         ? ((Integer) o).byteValue()
225                         : o;
226             }
227         }
228 
229         static class Chars extends BufferType<CharBuffer, Character> {
Chars(BufferKind k)230             Chars(BufferKind k) {
231                 super(k, CharBuffer.class, char.class);
232             }
233 
234             @Override
construct(int length, ByteOrder bo)235             CharBuffer construct(int length, ByteOrder bo) {
236                 switch (k) {
237                     case DIRECT:
238                         return ByteBuffer.allocateDirect(length * Character.BYTES).
239                                 order(bo).
240                                 asCharBuffer();
241                     case HEAP_VIEW:
242                         return ByteBuffer.allocate(length * Character.BYTES).
243                                 order(bo).
244                                 asCharBuffer();
245                     default:
246                     case HEAP:
247                         return CharBuffer.allocate(length);
248                 }
249             }
250 
251             @Override
convert(Object o)252             Object convert(Object o) {
253                 return o instanceof Integer
254                         ? (char) ((Integer) o).intValue()
255                         : o;
256             }
257 
transformToStringBuffer(CharBuffer c)258             CharBuffer transformToStringBuffer(CharBuffer c) {
259                 char[] chars = new char[c.remaining()];
260                 c.get(chars);
261                 return CharBuffer.wrap(new String(chars));
262             }
263         }
264 
265         static class Shorts extends BufferType<ShortBuffer, Short> {
Shorts(BufferKind k)266             Shorts(BufferKind k) {
267                 super(k, ShortBuffer.class, short.class);
268             }
269 
270             @Override
construct(int length, ByteOrder bo)271             ShortBuffer construct(int length, ByteOrder bo) {
272                 switch (k) {
273                     case DIRECT:
274                         return ByteBuffer.allocateDirect(length * Short.BYTES).
275                                 order(bo).
276                                 asShortBuffer();
277                     case HEAP_VIEW:
278                         return ByteBuffer.allocate(length * Short.BYTES).
279                                 order(bo).
280                                 asShortBuffer();
281                     default:
282                     case HEAP:
283                         return ShortBuffer.allocate(length);
284                 }
285             }
286 
287             @Override
convert(Object o)288             Object convert(Object o) {
289                 return o instanceof Integer
290                         ? ((Integer) o).shortValue()
291                         : o;
292             }
293         }
294 
295         static class Ints extends BufferType<IntBuffer, Integer> {
Ints(BufferKind k)296             Ints(BufferKind k) {
297                 super(k, IntBuffer.class, int.class);
298             }
299 
300             @Override
construct(int length, ByteOrder bo)301             IntBuffer construct(int length, ByteOrder bo) {
302                 switch (k) {
303                     case DIRECT:
304                         return ByteBuffer.allocateDirect(length * Integer.BYTES).
305                                 order(bo).
306                                 asIntBuffer();
307                     case HEAP_VIEW:
308                         return ByteBuffer.allocate(length * Integer.BYTES).
309                                 order(bo).
310                                 asIntBuffer();
311                     default:
312                     case HEAP:
313                         return IntBuffer.allocate(length);
314                 }
315             }
316 
convert(Object o)317             Object convert(Object o) {
318                 return o;
319             }
320         }
321 
322         static class Floats extends BufferType<FloatBuffer, Float> {
Floats(BufferKind k)323             Floats(BufferKind k) {
324                 super(k, FloatBuffer.class, float.class);
325             }
326 
327             @Override
construct(int length, ByteOrder bo)328             FloatBuffer construct(int length, ByteOrder bo) {
329                 switch (k) {
330                     case DIRECT:
331                         return ByteBuffer.allocateDirect(length * Float.BYTES).
332                                 order(bo).
333                                 asFloatBuffer();
334                     case HEAP_VIEW:
335                         return ByteBuffer.allocate(length * Float.BYTES).
336                                 order(bo).
337                                 asFloatBuffer();
338                     default:
339                     case HEAP:
340                         return FloatBuffer.allocate(length);
341                 }
342             }
343 
344             @Override
convert(Object o)345             Object convert(Object o) {
346                 return o instanceof Integer
347                         ? ((Integer) o).floatValue()
348                         : o;
349             }
350 
351             @Override
pairWiseEquals(FloatBuffer a, FloatBuffer b)352             boolean pairWiseEquals(FloatBuffer a, FloatBuffer b) {
353                 if (a.remaining() != b.remaining())
354                     return false;
355                 int p = a.position();
356                 for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
357                     float av = a.get(i);
358                     float bv = b.get(j);
359                     if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
360                         return false;
361                 }
362                 return true;
363             }
364         }
365 
366         static class Longs extends BufferType<LongBuffer, Long> {
Longs(BufferKind k)367             Longs(BufferKind k) {
368                 super(k, LongBuffer.class, long.class);
369             }
370 
371             @Override
construct(int length, ByteOrder bo)372             LongBuffer construct(int length, ByteOrder bo) {
373                 switch (k) {
374                     case DIRECT:
375                         return ByteBuffer.allocateDirect(length * Long.BYTES).
376                                 order(bo).
377                                 asLongBuffer();
378                     case HEAP_VIEW:
379                         return ByteBuffer.allocate(length * Long.BYTES).
380                                 order(bo).
381                                 asLongBuffer();
382                     default:
383                     case HEAP:
384                         return LongBuffer.allocate(length);
385                 }
386             }
387 
388             @Override
convert(Object o)389             Object convert(Object o) {
390                 return o instanceof Integer
391                         ? ((Integer) o).longValue()
392                         : o;
393             }
394         }
395 
396         static class Doubles extends BufferType<DoubleBuffer, Double> {
Doubles(BufferKind k)397             Doubles(BufferKind k) {
398                 super(k, DoubleBuffer.class, double.class);
399             }
400 
401             @Override
construct(int length, ByteOrder bo)402             DoubleBuffer construct(int length, ByteOrder bo) {
403                 switch (k) {
404                     case DIRECT:
405                         return ByteBuffer.allocateDirect(length * Double.BYTES).
406                                 order(bo).
407                                 asDoubleBuffer();
408                     case HEAP_VIEW:
409                         return ByteBuffer.allocate(length * Double.BYTES).
410                                 order(bo).
411                                 asDoubleBuffer();
412                     default:
413                     case HEAP:
414                         return DoubleBuffer.allocate(length);
415                 }
416             }
417 
418             @Override
convert(Object o)419             Object convert(Object o) {
420                 return o instanceof Integer
421                         ? ((Integer) o).doubleValue()
422                         : o;
423             }
424 
425             @Override
pairWiseEquals(DoubleBuffer a, DoubleBuffer b)426             boolean pairWiseEquals(DoubleBuffer a, DoubleBuffer b) {
427                 if (a.remaining() != b.remaining())
428                     return false;
429                 int p = a.position();
430                 for (int i = a.limit() - 1, j = b.limit() - 1; i >= p; i--, j--) {
431                     double av = a.get(i);
432                     double bv = b.get(j);
433                     if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
434                         return false;
435                 }
436                 return true;
437             }
438         }
439     }
440 
441     static Object[][] bufferTypes;
442 
443     @DataProvider
bufferTypesProvider()444     public static Object[][] bufferTypesProvider() {
445         if (bufferTypes == null) {
446             bufferTypes = new Object[][]{
447                     {new BufferType.Bytes(BufferKind.HEAP)},
448                     {new BufferType.Bytes(BufferKind.DIRECT)},
449                     {new BufferType.Chars(BufferKind.HEAP)},
450                     {new BufferType.Chars(BufferKind.HEAP_VIEW)},
451                     {new BufferType.Chars(BufferKind.DIRECT)},
452                     {new BufferType.Shorts(BufferKind.HEAP)},
453                     {new BufferType.Shorts(BufferKind.HEAP_VIEW)},
454                     {new BufferType.Shorts(BufferKind.DIRECT)},
455                     {new BufferType.Ints(BufferKind.HEAP)},
456                     {new BufferType.Ints(BufferKind.HEAP_VIEW)},
457                     {new BufferType.Ints(BufferKind.DIRECT)},
458                     {new BufferType.Floats(BufferKind.HEAP)},
459                     {new BufferType.Floats(BufferKind.HEAP_VIEW)},
460                     {new BufferType.Floats(BufferKind.DIRECT)},
461                     {new BufferType.Longs(BufferKind.HEAP)},
462                     {new BufferType.Longs(BufferKind.HEAP_VIEW)},
463                     {new BufferType.Longs(BufferKind.DIRECT)},
464                     {new BufferType.Doubles(BufferKind.HEAP)},
465                     {new BufferType.Doubles(BufferKind.HEAP_VIEW)},
466                     {new BufferType.Doubles(BufferKind.DIRECT)},
467             };
468         }
469         return bufferTypes;
470     }
471 
472 
473     static Object[][] floatbufferTypes;
474 
475     @DataProvider
floatBufferTypesProvider()476     public static Object[][] floatBufferTypesProvider() {
477         if (floatbufferTypes == null) {
478             LongFunction<Object> bTof = rb -> Float.intBitsToFloat((int) rb);
479             LongFunction<Object> bToD = Double::longBitsToDouble;
480 
481             floatbufferTypes = new Object[][]{
482                     // canonical and non-canonical NaNs
483                     // If conversion is a signalling NaN it may be subject to conversion to a
484                     // quiet NaN on some processors, even if a copy is performed
485                     // The tests assume that if conversion occurs it does not convert to the
486                     // canonical NaN
487                     new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x7fc00000L, 0x7f800001L, bTof},
488                     new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x7fc00000L, 0x7f800001L, bTof},
489                     new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x7fc00000L, 0x7f800001L, bTof},
490                     new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
491                     new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
492                     new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x7ff8000000000000L, 0x7ff0000000000001L, bToD},
493 
494                     // +0.0 and -0.0
495                     new Object[]{new BufferType.Floats(BufferKind.HEAP), 0x0L, 0x80000000L, bTof},
496                     new Object[]{new BufferType.Floats(BufferKind.HEAP_VIEW), 0x0L, 0x80000000L, bTof},
497                     new Object[]{new BufferType.Floats(BufferKind.DIRECT), 0x0L, 0x80000000L, bTof},
498                     new Object[]{new BufferType.Doubles(BufferKind.HEAP), 0x0L, 0x8000000000000000L, bToD},
499                     new Object[]{new BufferType.Doubles(BufferKind.HEAP_VIEW), 0x0L, 0x8000000000000000L, bToD},
500                     new Object[]{new BufferType.Doubles(BufferKind.DIRECT), 0x0L, 0x8000000000000000L, bToD},
501             };
502         }
503         return floatbufferTypes;
504     }
505 
506 
507     static Object[][] charBufferTypes;
508 
509     @DataProvider
charBufferTypesProvider()510     public static Object[][] charBufferTypesProvider() {
511         if (charBufferTypes == null) {
512             charBufferTypes = new Object[][]{
513                     {new BufferType.Chars(BufferKind.HEAP)},
514                     {new BufferType.Chars(BufferKind.HEAP_VIEW)},
515                     {new BufferType.Chars(BufferKind.DIRECT)},
516             };
517         }
518         return charBufferTypes;
519     }
520 
521 
522     // Tests all primitive buffers
523     @Test(dataProvider = "bufferTypesProvider")
testBuffers(BufferType<Buffer, Buffer> bufferType)524     public void testBuffers(BufferType<Buffer, Buffer> bufferType) {
525         // Test with buffers of the same byte order (BE)
526         BiFunction<BufferType<Buffer, Buffer>, Integer, Buffer> constructor = (at, s) -> {
527             Buffer a = at.construct(s);
528             for (int x = 0; x < s; x++) {
529                 at.set(a, x, x % 8);
530             }
531             return a;
532         };
533 
534         // Test with buffers of different byte order
535         if (bufferType.elementType != byte.class &&
536                 (bufferType.k == BufferKind.HEAP_VIEW ||
537                         bufferType.k == BufferKind.DIRECT)) {
538 
539             BiFunction<BufferType<Buffer, Buffer>, Integer, Buffer> leConstructor = (at, s) -> {
540                 Buffer a = at.construct(s, ByteOrder.LITTLE_ENDIAN);
541                 for (int x = 0; x < s; x++) {
542                     at.set(a, x, x % 8);
543                 }
544                 return a;
545             };
546             testBufferType(bufferType, constructor, leConstructor);
547         }
548     }
549 
550     // Tests float and double buffers with edge-case values (NaN, -0.0, +0.0)
551     @Test(dataProvider = "floatBufferTypesProvider")
testFloatBuffers( BufferType<Buffer, Float> bufferType, long rawBitsA, long rawBitsB, LongFunction<Object> bitsToFloat)552     public void testFloatBuffers(
553             BufferType<Buffer, Float> bufferType,
554             long rawBitsA, long rawBitsB,
555             LongFunction<Object> bitsToFloat) {
556         Object av = bitsToFloat.apply(rawBitsA);
557         Object bv = bitsToFloat.apply(rawBitsB);
558 
559         BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allAs = (at, s) -> {
560             Buffer b = at.construct(s);
561             for (int x = 0; x < s; x++) {
562                 at.set(b, x, av);
563             }
564             return b;
565         };
566 
567         BiFunction<BufferType<Buffer, Float>, Integer, Buffer> allBs = (at, s) -> {
568             Buffer b = at.construct(s);
569             for (int x = 0; x < s; x++) {
570                 at.set(b, x, bv);
571             }
572             return b;
573         };
574 
575         BiFunction<BufferType<Buffer, Float>, Integer, Buffer> halfBs = (at, s) -> {
576             Buffer b = at.construct(s);
577             for (int x = 0; x < s / 2; x++) {
578                 at.set(b, x, bv);
579             }
580             for (int x = s / 2; x < s; x++) {
581                 at.set(b, x, 1);
582             }
583             return b;
584         };
585 
586         // Validation check
587         int size = arraySizeFor(bufferType.elementType);
588         Assert.assertTrue(bufferType.pairWiseEquals(allAs.apply(bufferType, size),
589                 allBs.apply(bufferType, size)));
590         Assert.assertTrue(bufferType.equals(allAs.apply(bufferType, size),
591                 allBs.apply(bufferType, size)));
592 
593         testBufferType(bufferType, allAs, allBs);
594         testBufferType(bufferType, allAs, halfBs);
595     }
596 
597     // Tests CharBuffer for region sources and CharSequence sources
598     @Test(dataProvider = "charBufferTypesProvider")
testCharBuffers(BufferType.Chars charBufferType)599     public void testCharBuffers(BufferType.Chars charBufferType) {
600 
601         BiFunction<BufferType.Chars, Integer, CharBuffer> constructor = (at, s) -> {
602             CharBuffer a = at.construct(s);
603             for (int x = 0; x < s; x++) {
604                 at.set(a, x, x % 8);
605             }
606             return a;
607         };
608 
609         BiFunction<BufferType.Chars, Integer, CharBuffer> constructorX = constructor.
610                 andThen(charBufferType::transformToStringBuffer);
611 
612         testBufferType(charBufferType, constructor, constructorX);
613     }
614 
615 
616     <B extends Buffer, E, BT extends BufferType<B, E>>
testBufferType(BT bt, BiFunction<BT, Integer, B> aConstructor, BiFunction<BT, Integer, B> bConstructor)617     void testBufferType(BT bt,
618             BiFunction<BT, Integer, B> aConstructor,
619             BiFunction<BT, Integer, B> bConstructor) {
620         int n = arraySizeFor(bt.elementType);
621 
622         for (boolean dupOtherwiseSlice : new boolean[]{ false, true }) {
623             for (int s : ranges(0, n)) {
624                 B a = aConstructor.apply(bt, s);
625                 B b = bConstructor.apply(bt, s);
626 
627                 for (int aFrom : ranges(0, s)) {
628                     for (int aTo : ranges(aFrom, s)) {
629                         int aLength = aTo - aFrom;
630 
631                         B as = aLength != s
632                                 ? bt.slice(a, aFrom, aTo, dupOtherwiseSlice)
633                                 : a;
634 
635                         for (int bFrom : ranges(0, s)) {
636                             for (int bTo : ranges(bFrom, s)) {
637                                 int bLength = bTo - bFrom;
638 
639                                 B bs = bLength != s
640                                         ? bt.slice(b, bFrom, bTo, dupOtherwiseSlice)
641                                         : b;
642 
643                                 boolean eq = bt.pairWiseEquals(as, bs);
644                                 Assert.assertEquals(bt.equals(as, bs), eq);
645                                 Assert.assertEquals(bt.equals(bs, as), eq);
646                                 if (eq) {
647                                     Assert.assertEquals(bt.compare(as, bs), 0);
648                                     Assert.assertEquals(bt.compare(bs, as), 0);
649 
650                                     // If buffers are equal, there shall be no mismatch
651                                     Assert.assertEquals(bt.mismatch(as, bs), -1);
652                                     Assert.assertEquals(bt.mismatch(bs, as), -1);
653                                 }
654                                 else {
655                                     int aCb = bt.compare(as, bs);
656                                     int bCa = bt.compare(bs, as);
657                                     int v = Integer.signum(aCb) * Integer.signum(bCa);
658                                     Assert.assertTrue(v == -1);
659 
660                                     int aMs = bt.mismatch(as, bs);
661                                     int bMs = bt.mismatch(bs, as);
662                                     Assert.assertNotEquals(aMs, -1);
663                                     Assert.assertEquals(aMs, bMs);
664                                 }
665                             }
666                         }
667                         // TODO(b/271236407): fix this
668 //                            if (aLength > 0 && !a.isReadOnly()) {
669 //                                for (int i = aFrom; i < aTo; i++) {
670 //                                    B c = aConstructor.apply(bt, a.capacity());
671 //                                    B cs = aLength != s
672 //                                            ? bt.slice(c, aFrom, aTo, dupOtherwiseSlice)
673 //                                            : c;
674 //
675 //                                    // Create common prefix with a length of i - aFrom
676 //                                    bt.set(c, i, -1);
677 //
678 //                                    Assert.assertFalse(bt.equals(c, a));
679 //
680 //                                    int cCa = bt.compare(cs, as);
681 //                                    int aCc = bt.compare(as, cs);
682 //                                    int v = Integer.signum(cCa) * Integer.signum(aCc);
683 //                                    Assert.assertTrue(v == -1);
684 //
685 //                                    int cMa = bt.mismatch(cs, as);
686 //                                    int aMc = bt.mismatch(as, cs);
687 //                                    Assert.assertEquals(cMa, aMc);
688 //                                    Assert.assertEquals(cMa, i - aFrom);
689 //                                }
690 //                            }
691                     }
692                 }
693             }
694         }
695     }
696 
ranges(int from, int to)697     static int[] ranges(int from, int to) {
698         int width = to - from;
699         switch (width) {
700             case 0:
701                 return new int[]{};
702             case 1:
703                 return new int[]{from, to};
704             case 2:
705                 return new int[]{from, from + 1, to};
706             case 3:
707                 return new int[]{from, from + 1, from + 2, to};
708             default:
709                 return IntStream.of(from, from + 1, from + 2, to / 2 - 1, to / 2, to / 2 + 1, to - 2, to - 1, to)
710                         .filter(i -> i >= from && i <= to)
711                         .distinct().toArray();
712         }
713     }
714 }
715