private static List<ListenableFuture<?>> testAllSlices(
     String id, Object[] btree, NavigableSet<Integer> canon) {
   List<ListenableFuture<?>> waitFor = new ArrayList<>();
   testAllSlices(id + " ASC", new BTreeSet<>(btree, naturalOrder()), canon, true, waitFor);
   testAllSlices(
       id + " DSC",
       new BTreeSet<Integer>(btree, naturalOrder()).descendingSet(),
       canon.descendingSet(),
       false,
       waitFor);
   return waitFor;
 }
 private static void testAllSlices(
     String id,
     NavigableSet<Integer> btree,
     NavigableSet<Integer> canon,
     boolean ascending,
     List<ListenableFuture<?>> results) {
   testOneSlice(id, btree, canon, results);
   for (Integer lb : range(canon.size(), Integer.MIN_VALUE, ascending)) {
     // test head/tail sets
     testOneSlice(
         String.format("%s->[..%d)", id, lb),
         btree.headSet(lb, true),
         canon.headSet(lb, true),
         results);
     testOneSlice(
         String.format("%s->(..%d)", id, lb),
         btree.headSet(lb, false),
         canon.headSet(lb, false),
         results);
     testOneSlice(
         String.format("%s->(%d..]", id, lb),
         btree.tailSet(lb, true),
         canon.tailSet(lb, true),
         results);
     testOneSlice(
         String.format("%s->(%d..]", id, lb),
         btree.tailSet(lb, false),
         canon.tailSet(lb, false),
         results);
     for (Integer ub : range(canon.size(), lb, ascending)) {
       // test subsets
       testOneSlice(
           String.format("%s->[%d..%d]", id, lb, ub),
           btree.subSet(lb, true, ub, true),
           canon.subSet(lb, true, ub, true),
           results);
       testOneSlice(
           String.format("%s->(%d..%d]", id, lb, ub),
           btree.subSet(lb, false, ub, true),
           canon.subSet(lb, false, ub, true),
           results);
       testOneSlice(
           String.format("%s->[%d..%d)", id, lb, ub),
           btree.subSet(lb, true, ub, false),
           canon.subSet(lb, true, ub, false),
           results);
       testOneSlice(
           String.format("%s->(%d..%d)", id, lb, ub),
           btree.subSet(lb, false, ub, false),
           canon.subSet(lb, false, ub, false),
           results);
     }
   }
 }
    RandomSelection select(boolean narrow, boolean mixInNotPresentItems, boolean permitReversal) {
      ThreadLocalRandom random = ThreadLocalRandom.current();
      NavigableSet<Integer> canonicalSet = this.canonical;
      BTreeSet<Integer> testAsSet = this.test;
      List<Integer> canonicalList = new ArrayList<>(canonicalSet);
      BTreeSet<Integer> testAsList = this.test;

      Assert.assertEquals(canonicalSet.size(), testAsSet.size());
      Assert.assertEquals(canonicalList.size(), testAsList.size());

      // sometimes select keys first, so we cover full range
      List<Integer> allKeys = randomKeys(canonical, mixInNotPresentItems);
      List<Integer> keys = allKeys;

      int narrowCount = random.nextInt(3);
      while (narrow && canonicalList.size() > 10 && keys.size() > 10 && narrowCount-- > 0) {
        boolean useLb = random.nextBoolean();
        boolean useUb = random.nextBoolean();
        if (!(useLb | useUb)) continue;

        // select a range smaller than the total span when we have more narrowing iterations left
        int indexRange = keys.size() / (narrowCount + 1);

        boolean lbInclusive = true;
        Integer lbKey = canonicalList.get(0);
        int lbKeyIndex = 0, lbIndex = 0;
        boolean ubInclusive = true;
        Integer ubKey = canonicalList.get(canonicalList.size() - 1);
        int ubKeyIndex = keys.size(), ubIndex = canonicalList.size();

        if (useLb) {
          lbKeyIndex = random.nextInt(0, indexRange - 1);
          Integer candidate = keys.get(lbKeyIndex);
          if (useLb = (candidate > lbKey && candidate <= ubKey)) {
            lbInclusive = random.nextBoolean();
            lbKey = keys.get(lbKeyIndex);
            lbIndex = Collections.binarySearch(canonicalList, lbKey);
            if (lbIndex >= 0 && !lbInclusive) lbIndex++;
            else if (lbIndex < 0) lbIndex = -1 - lbIndex;
          }
        }
        if (useUb) {
          ubKeyIndex =
              random.nextInt(Math.max(lbKeyIndex, keys.size() - indexRange), keys.size() - 1);
          Integer candidate = keys.get(ubKeyIndex);
          if (useUb = (candidate < ubKey && candidate >= lbKey)) {
            ubInclusive = random.nextBoolean();
            ubKey = keys.get(ubKeyIndex);
            ubIndex = Collections.binarySearch(canonicalList, ubKey);
            if (ubIndex >= 0 && ubInclusive) {
              ubIndex++;
            } else if (ubIndex < 0) ubIndex = -1 - ubIndex;
          }
        }
        if (ubIndex < lbIndex) {
          ubIndex = lbIndex;
          ubKey = lbKey;
          ubInclusive = false;
        }

        canonicalSet =
            !useLb
                ? canonicalSet.headSet(ubKey, ubInclusive)
                : !useUb
                    ? canonicalSet.tailSet(lbKey, lbInclusive)
                    : canonicalSet.subSet(lbKey, lbInclusive, ubKey, ubInclusive);
        testAsSet =
            !useLb
                ? testAsSet.headSet(ubKey, ubInclusive)
                : !useUb
                    ? testAsSet.tailSet(lbKey, lbInclusive)
                    : testAsSet.subSet(lbKey, lbInclusive, ubKey, ubInclusive);

        keys = keys.subList(lbKeyIndex, ubKeyIndex);
        canonicalList = canonicalList.subList(lbIndex, ubIndex);
        testAsList = testAsList.subList(lbIndex, ubIndex);

        Assert.assertEquals(canonicalSet.size(), testAsSet.size());
        Assert.assertEquals(canonicalList.size(), testAsList.size());
      }

      // possibly restore full set of keys, to test case where we are provided existing keys that
      // are out of bounds
      if (keys != allKeys && random.nextBoolean()) keys = allKeys;

      Comparator<Integer> comparator = naturalOrder();
      if (permitReversal && random.nextBoolean()) {
        if (allKeys != keys) keys = new ArrayList<>(keys);
        if (canonicalSet != canonical) canonicalList = new ArrayList<>(canonicalList);
        Collections.reverse(keys);
        Collections.reverse(canonicalList);
        testAsList = testAsList.descendingSet();

        canonicalSet = canonicalSet.descendingSet();
        testAsSet = testAsSet.descendingSet();
        comparator = reverseOrder();
      }

      Assert.assertEquals(canonicalSet.size(), testAsSet.size());
      Assert.assertEquals(canonicalList.size(), testAsList.size());
      if (!canonicalSet.isEmpty()) {
        Assert.assertEquals(canonicalSet.first(), canonicalList.get(0));
        Assert.assertEquals(canonicalSet.last(), canonicalList.get(canonicalList.size() - 1));
        Assert.assertEquals(canonicalSet.first(), testAsSet.first());
        Assert.assertEquals(canonicalSet.last(), testAsSet.last());
        Assert.assertEquals(canonicalSet.first(), testAsList.get(0));
        Assert.assertEquals(canonicalSet.last(), testAsList.get(testAsList.size() - 1));
      }

      return new RandomSelection(
          keys, canonicalSet, testAsSet, canonicalList, testAsList, comparator);
    }