/*******************************************************************************
* Copyright (c) 2014, 2015 Manumitting Technologies Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Brian de Alwis (MTI) - initial API and implementation
******************************************************************************/
package org.eclipse.e4.ui.tests.workbench;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.e4.ui.internal.workbench.TopologicalSort;
import org.junit.Test;
/**
* A set of tests for the {@link TopologicalSort} class
*/
public class TopoSortTests {
/** Should this sorter configure as requirements, dependencies, or both */
enum Type {
REQUIREMENTS, DEPENDENCIES, BOTH
}
/**
* A simple topological sorter that uses the test data from
* http://www.cs.sunysb.edu/~algorith/files/topological-sorting.shtml we
* interpret arrows as A → B means B is a requirement of A, or A is a
* dependency of B. The input data is 1 through 10.
*/
static class TestSorter extends TopologicalSort<Integer, Integer> {
Type type = Type.REQUIREMENTS;
/** The test data */
public Integer[] getTestData() {
return new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
}
@Override
protected Collection<Integer> getRequirements(Integer value) {
if (type == Type.DEPENDENCIES) {
return Collections.emptyList();
}
switch (value) {
case 1:
return Collections.emptyList();
case 2:
case 3:
case 5:
case 7:
return Collections.singleton(1);
case 4:
return Collections.singleton(2);
case 6:
return Arrays.asList(2, 3);
case 8:
return Collections.singleton(4);
case 9:
return Collections.singleton(3);
case 10:
return Arrays.asList(2, 5);
default:
throw new IllegalArgumentException(value.toString());
}
}
@Override
protected Collection<Integer> getDependencies(Integer value) {
if (type == Type.REQUIREMENTS) {
return Collections.emptyList();
}
// this uses the example from
// <http://www.cs.sunysb.edu/~algorith/files/topological-sorting.shtml>
// we interpret arrows as A -> B means A is the successor of B, or A
// depends on B
switch (value) {
case 1:
return Arrays.asList(2, 3, 5, 7);
case 2:
return Arrays.asList(4, 6, 10);
case 3:
return Arrays.asList(6, 9);
case 4:
return Arrays.asList(8);
case 5:
return Arrays.asList(10);
case 6:
case 7:
case 8:
case 9:
case 10:
return Collections.emptyList();
default:
throw new IllegalArgumentException(value.toString());
}
}
@Override
protected Integer getId(Integer o) {
return o;
}
}
@Test
public void testTopoSorter() {
TestSorter ts = new TestSorter();
for (Type type : Type.values()) {
ts.type = type;
List<Integer> results = Arrays.asList(ts.sort(ts.getTestData()));
assertTrue(results.indexOf(1) < results.indexOf(2));
assertTrue(results.indexOf(1) < results.indexOf(3));
assertTrue(results.indexOf(1) < results.indexOf(5));
assertTrue(results.indexOf(1) < results.indexOf(7));
assertTrue(results.indexOf(2) < results.indexOf(4));
assertTrue(results.indexOf(2) < results.indexOf(6));
assertTrue(results.indexOf(2) < results.indexOf(10));
assertTrue(results.indexOf(3) < results.indexOf(6));
assertTrue(results.indexOf(3) < results.indexOf(9));
assertTrue(results.indexOf(4) < results.indexOf(8));
assertTrue(results.indexOf(5) < results.indexOf(10));
}
}
/**
* Test cycles: A → B, B → C, C → A, D → A. All nodes
* have out-degree 1, but A has in-degree 2. A, B, C must be output before
* D.
*/
static class CycleTestSorter extends TopologicalSort<String, String> {
Type type = Type.REQUIREMENTS;
/** The test data */
public String[] getTestData() {
return new String[] { "A", "B", "C", "D" };
}
@Override
protected String getId(String o) {
return o;
}
@Override
protected Collection<String> getRequirements(String id) {
if (type == Type.DEPENDENCIES) {
return null;
}
if (id.equals("A")) {
return Collections.singleton("B");
} else if (id.equals("B")) {
return Collections.singleton("C");
} else if (id.equals("C")) {
return Collections.singleton("A");
} else if (id.equals("D")) {
return Collections.singleton("A");
}
throw new IllegalArgumentException(id);
}
@Override
protected Collection<String> getDependencies(String id) {
if (type == Type.REQUIREMENTS) {
return null;
}
if (id.equals("A")) {
return Arrays.asList("C", "D");
} else if (id.equals("B")) {
return Collections.singleton("A");
} else if (id.equals("C")) {
return Collections.singleton("B");
} else if (id.equals("D")) {
return null;
}
throw new IllegalArgumentException(id);
}
}
@Test
public void testCycles() {
CycleTestSorter ts = new CycleTestSorter();
for (Type type : Type.values()) {
ts.type = type;
List<String> results = Arrays.asList(ts.sort(ts.getTestData()));
assertTrue(results.indexOf("A") < results.indexOf("D"));
assertTrue(results.indexOf("B") < results.indexOf("D"));
assertTrue(results.indexOf("C") < results.indexOf("D"));
assertTrue(results.indexOf("A") < results.indexOf("D"));
}
}
}