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