blob: 0dc290e600dc37b84a9b5b9c83912b370713501b [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.impala.util;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Set;
import org.junit.Test;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* Unit tests for the DisjointSet data structure.
*/
public class TestDisjointSet {
@Test
public void testMakeSet() throws Exception {
DisjointSet<Integer> ds = new DisjointSet<Integer>();
// Expect success.
ds.makeSet(1);
assertTrue(ds.get(1).contains(1));
ds.makeSet(2);
assertTrue(ds.get(2).contains(2));
ds.checkConsistency();
Set<Integer> existingSet = ds.get(1);
// Manually tamper with the item set for testing purposes.
existingSet.add(6);
existingSet.add(7);
// The item set already exists.
try {
ds.makeSet(1);
fail("makeSet() on an item with an existing item set did not fail");
} catch (Exception e) {
// Check that the failed makeSet didn't change the existing set.
assertTrue(existingSet == ds.get(1));
assertTrue(existingSet.contains(1));
assertTrue(existingSet.contains(6));
assertTrue(existingSet.contains(7));
}
// Tests detecting the inconsistency due to the manual modifications.
try {
ds.checkConsistency();
fail("Failed to detect an inconsistency in the DisjointSet data structure.");
} catch (Exception e) {
}
}
@Test
public void testUnion() throws Exception {
DisjointSet<Integer> ds = new DisjointSet<Integer>();
ds.makeSet(1);
// test idempotence
assertFalse(ds.union(1, 1));
assertTrue(ds.get(1).contains(1) && ds.get(1).size() == 1);
ds.checkConsistency();
// test creating a new single-item set with union()
assertTrue(ds.union(2, 2));
assertTrue(ds.get(2).contains(2) && ds.get(2).size() == 1);
ds.checkConsistency();
// test creating a multi-item set with union()
assertTrue(ds.union(3, 4));
assertTrue(ds.get(3) == ds.get(4) && ds.get(3).contains(4) && ds.get(4).contains(3));
ds.checkConsistency();
// test idempotence
assertFalse(ds.union(3, 4));
assertTrue(ds.get(3) == ds.get(4) && ds.get(3).contains(4) && ds.get(4).contains(3));
ds.checkConsistency();
// test merging an existing item set with a non-existent item
assertTrue(ds.union(4, 5));
assertTrue(ds.get(4) == ds.get(5) && ds.get(4).contains(5)
&& ds.get(4).containsAll(Lists.newArrayList(3, 4, 5)));
assertTrue(ds.union(6, 4));
assertTrue(ds.get(4) == ds.get(6) && ds.get(6).contains(4)
&& ds.get(4).containsAll(Lists.newArrayList(3, 4, 5, 6)));
// already in the same set
assertFalse(ds.union(4, 6));
ds.checkConsistency();
// test merging two existing single-item item sets
assertTrue(ds.union(1, 2));
assertTrue(ds.get(1) == ds.get(2) &&
ds.get(1).containsAll(Lists.newArrayList(1, 2)));
ds.checkConsistency();
// test merging two multi-item item sets
assertTrue(ds.union(1, 3));
assertTrue(ds.get(1) == ds.get(3) &&
ds.get(1).containsAll(Lists.newArrayList(1, 2, 3, 4, 5, 6)));
// already in the same set
for (int i = 1; i <= 6; ++i) {
for (int j = 1; j <= 6; ++j) {
assertFalse(ds.union(i, j));
}
}
ds.checkConsistency();
}
@Test
public void testBulkUnion() throws Exception {
DisjointSet<Integer> ds = new DisjointSet<Integer>();
// test creating a new single-item set
assertTrue(ds.bulkUnion(Sets.newHashSet(1)));
assertTrue(ds.get(1).contains(1) && ds.get(1).size() == 1);
ds.checkConsistency();
// test creating a new multi-item item set
assertTrue(ds.bulkUnion(Sets.newHashSet(2, 3, 4)));
assertTrue(ds.get(2) == ds.get(3) && ds.get(2) == ds.get(4)
&& ds.get(2).containsAll(Lists.newArrayList(2, 3, 4)));
// already in the same set
for (int i = 2; i <= 4; ++i) {
for (int j = 2; j <= 4; ++j) {
assertFalse(ds.union(i, j));
assertFalse(ds.bulkUnion(Sets.newHashSet(i, j)));
}
}
ds.checkConsistency();
// create another new multi-item item set
assertTrue(ds.bulkUnion(Sets.newHashSet(5, 6, 7, 8)));
assertTrue(ds.get(5) == ds.get(6) && ds.get(6) == ds.get(7) && ds.get(7) == ds.get(8)
&& ds.get(5).containsAll(Lists.newArrayList(5, 6, 7, 8)));
ds.checkConsistency();
// merge all existing item sets
assertTrue(ds.bulkUnion(Sets.newHashSet(1, 3, 8)));
assertTrue(ds.get(1) == ds.get(2) && ds.get(2) == ds.get(3) && ds.get(3) == ds.get(4)
&& ds.get(4) == ds.get(5) && ds.get(5) == ds.get(6) && ds.get(6) == ds.get(7)
&& ds.get(7) == ds.get(8)
&& ds.get(1).containsAll(Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8)));
ds.checkConsistency();
}
/**
* IMPALA-4916: Tests that the set of item sets is maintained correctly.
*/
@Test
public void testUniqueSets() throws Exception {
DisjointSet<Integer> ds = new DisjointSet<Integer>();
int uniqueElements = 100;
// Generate several 2-element item sets.
for (int i = 0; i < uniqueElements; i += 2) ds.union(i, i + 1);
// Connect several item sets into one big item set. This stresses the logic
// of maintaining the set of item sets.
for (int i = uniqueElements/2; i < uniqueElements; ++i) ds.union(i, i + 1);
ds.checkConsistency();
}
}