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); } } }
/** tailSet returns set with keys in requested range */ public void testDescendingTailSetContents() { NavigableSet set = dset5(); SortedSet sm = set.tailSet(m2); assertFalse(sm.contains(m1)); assertTrue(sm.contains(m2)); assertTrue(sm.contains(m3)); assertTrue(sm.contains(m4)); assertTrue(sm.contains(m5)); Iterator i = sm.iterator(); Object k; k = (Integer) (i.next()); assertEquals(m2, k); k = (Integer) (i.next()); assertEquals(m3, k); k = (Integer) (i.next()); assertEquals(m4, k); k = (Integer) (i.next()); assertEquals(m5, k); assertFalse(i.hasNext()); SortedSet ssm = sm.tailSet(m4); assertEquals(m4, ssm.first()); assertEquals(m5, ssm.last()); assertTrue(ssm.remove(m4)); assertEquals(1, ssm.size()); assertEquals(3, sm.size()); assertEquals(4, set.size()); }
/** tailSet returns set with keys in requested range */ public void testTailSetContents() { NavigableSet set = set5(); SortedSet sm = set.tailSet(two); assertFalse(sm.contains(one)); assertTrue(sm.contains(two)); assertTrue(sm.contains(three)); assertTrue(sm.contains(four)); assertTrue(sm.contains(five)); Iterator i = sm.iterator(); Object k; k = (Integer) (i.next()); assertEquals(two, k); k = (Integer) (i.next()); assertEquals(three, k); k = (Integer) (i.next()); assertEquals(four, k); k = (Integer) (i.next()); assertEquals(five, k); assertFalse(i.hasNext()); SortedSet ssm = sm.tailSet(four); assertEquals(four, ssm.first()); assertEquals(five, ssm.last()); assertTrue(ssm.remove(four)); assertEquals(1, ssm.size()); assertEquals(3, sm.size()); assertEquals(4, set.size()); }
@GwtIncompatible("NavigableSet") public void testUnmodifiableNavigableSet() { TreeSet<Integer> mod = Sets.newTreeSet(); mod.add(1); mod.add(2); mod.add(3); NavigableSet<Integer> unmod = unmodifiableNavigableSet(mod); /* Unmodifiable is a view. */ mod.add(4); assertTrue(unmod.contains(4)); assertTrue(unmod.descendingSet().contains(4)); ensureNotDirectlyModifiable(unmod); ensureNotDirectlyModifiable(unmod.descendingSet()); ensureNotDirectlyModifiable(unmod.headSet(2)); ensureNotDirectlyModifiable(unmod.headSet(2, true)); ensureNotDirectlyModifiable(unmod.tailSet(2)); ensureNotDirectlyModifiable(unmod.tailSet(2, true)); ensureNotDirectlyModifiable(unmod.subSet(1, 3)); ensureNotDirectlyModifiable(unmod.subSet(1, true, 3, true)); /* UnsupportedOperationException on indirect modifications. */ NavigableSet<Integer> reverse = unmod.descendingSet(); try { reverse.add(4); fail("UnsupportedOperationException expected"); } catch (UnsupportedOperationException expected) { } try { reverse.addAll(Collections.singleton(4)); fail("UnsupportedOperationException expected"); } catch (UnsupportedOperationException expected) { } try { reverse.remove(4); fail("UnsupportedOperationException expected"); } catch (UnsupportedOperationException expected) { } }
@SuppressWarnings("EmptyCatchBlock") public void testUnmodifiability() { TreeSet<Integer> mod = Sets.newTreeSet(); mod.add(1); mod.add(2); mod.add(3); NavigableSet<Integer> unmod = new UnmodifiableNavigableSet<Integer>(mod); mod.add(4); assertTrue(unmod.contains(4)); assertTrue(unmod.descendingSet().contains(4)); ensureNotDirectlyModifiable(unmod); ensureNotDirectlyModifiable(unmod.descendingSet()); ensureNotDirectlyModifiable(unmod.headSet(2)); ensureNotDirectlyModifiable(unmod.headSet(2, true)); ensureNotDirectlyModifiable(unmod.tailSet(2)); ensureNotDirectlyModifiable(unmod.tailSet(2, true)); ensureNotDirectlyModifiable(unmod.subSet(1, 3)); ensureNotDirectlyModifiable(unmod.subSet(1, true, 3, true)); NavigableSet<Integer> reverse = unmod.descendingSet(); try { reverse.add(4); fail("UnsupportedOperationException expected"); } catch (UnsupportedOperationException expected) { } try { reverse.addAll(Collections.singleton(4)); fail("UnsupportedOperationException expected"); } catch (UnsupportedOperationException expected) { } try { reverse.remove(4); fail("UnsupportedOperationException expected"); } catch (UnsupportedOperationException expected) { } }
/** * Finds range of server deltas needed to transform against, then transforms all client ops * against the server ops. */ private VersionedWaveletDelta transformSubmittedDelta( WaveletDelta submittedDelta, HashedVersion appliedVersion) throws OperationException, InvalidHashException { NavigableSet<VersionedWaveletDelta> serverDeltas = deserializedTransformedDeltas.tailSet( deserializedTransformedDeltas.floor( emptyDeserializedDeltaAtVersion(appliedVersion.getVersion())), true); if (serverDeltas.size() == 0) { LOG.warning("Got empty server set, but not sumbitting to head! " + submittedDelta); // Not strictly an invalid hash, but it's a related issue throw new InvalidHashException("Cannot submit to head"); } // Confirm that the target version/hash of this delta is valid. if (!serverDeltas.first().version.equals(appliedVersion)) { LOG.warning( "Mismatched hashes: expected: " + serverDeltas.first().version + " got: " + appliedVersion); // Don't leak the hash to the client in the error message. throw new InvalidHashException("Mismatched hashes at version " + appliedVersion.getVersion()); } ParticipantId clientAuthor = submittedDelta.getAuthor(); List<WaveletOperation> clientOps = submittedDelta.getOperations(); for (VersionedWaveletDelta d : serverDeltas) { // If the client delta transforms to nothing before we've traversed all the server // deltas, return the version at which the delta was obliterated (rather than the // current version) to ensure that delta submission is idempotent. if (clientOps.isEmpty()) { return new VersionedWaveletDelta(new WaveletDelta(clientAuthor, clientOps), d.version); } ParticipantId serverAuthor = d.delta.getAuthor(); List<WaveletOperation> serverOps = d.delta.getOperations(); if (clientAuthor.equals(serverAuthor) && clientOps.equals(serverOps)) { return d; } clientOps = transformOps(clientOps, clientAuthor, serverOps, serverAuthor); } return new VersionedWaveletDelta(new WaveletDelta(clientAuthor, clientOps), currentVersion); }
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); }