/*
* JCarder -- cards Java programs to keep threads disentangled
*
* Copyright (C) 2006-2007 Enea AB
* Copyright (C) 2007 Ulrik Svensson
* Copyright (C) 2007 Joel Rosdahl
*
* This program is made available under the GNU GPL version 2, with a special
* exception for linking with JUnit. See the accompanying file LICENSE.txt for
* details.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*/
package com.enea.jcarder.analyzer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.enea.jcarder.analyzer.Cycle;
import com.enea.jcarder.analyzer.CycleDetector;
import com.enea.jcarder.analyzer.LockEdge;
import com.enea.jcarder.analyzer.LockGraphBuilder;
import com.enea.jcarder.analyzer.LockNode;
import com.enea.jcarder.util.logging.Logger;
/*
* The purpose of this junit class is to test the class CycleDetector.
*
* TODO Some important methods in CycleDetector are not tested yet.
*/
public final class TestCycleDetector {
LockGraphBuilder mBuilder;
CycleDetector mCycleDetector;
LinkedList<LockNode> mNodes;
HashSet<Cycle> mExpectedCycles;
@Before
public void setUp() throws Exception {
mBuilder = new LockGraphBuilder();
mCycleDetector = new CycleDetector(new Logger(null));
mNodes = new LinkedList<LockNode>();
mExpectedCycles = new HashSet<Cycle>();
}
private LockEdge addEdge(int from, int to) {
return addEdge(from, to, -1);
}
private LockEdge addEdge(int from, int to, int threadId) {
final LockNode sourceLock = mBuilder.getLockNode(from);
final LockNode targetLock = mBuilder.getLockNode(to);
final LockEdge edge = new LockEdge(sourceLock,
targetLock,
threadId,
-1,
-1);
sourceLock.addOutgoingEdge(edge);
if (!mNodes.contains(sourceLock)) {
mNodes.add(sourceLock);
}
if (!mNodes.contains(sourceLock)) {
mNodes.add(sourceLock);
}
return edge;
}
private void addExpectedCycle(LockEdge[] edges) {
Cycle cycle = new Cycle(Arrays.asList(edges));
mExpectedCycles.add(cycle);
}
private void assertExpectedCycles() {
Assert.assertEquals(mExpectedCycles, mCycleDetector.getCycles());
}
@Test
public void testNoCycle() throws Exception {
addEdge(1, 2);
addEdge(2, 3);
addEdge(1, 3);
addEdge(3, 4);
mCycleDetector.analyzeLockNodes(mNodes);
assertExpectedCycles();
}
@Test
public void testSmallCycle() throws Exception {
LockEdge e1 = addEdge(1, 2);
LockEdge e2 = addEdge(2, 1);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e2});
assertExpectedCycles();
}
@Test
public void testCycle() throws Exception {
addEdge(1, 2);
LockEdge e2 = addEdge(2, 3);
LockEdge e3 = addEdge(3, 4);
LockEdge e4 = addEdge(4, 2);
addEdge(4, 5);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e2, e3, e4});
assertExpectedCycles();
}
@Test
public void testCyclesWithTwoPaths() throws Exception {
addEdge(1, 2);
LockEdge e2 = addEdge(2, 3);
LockEdge e3 = addEdge(3, 4);
LockEdge e4 = addEdge(2, 4);
LockEdge e5 = addEdge(4, 2);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e2, e3, e5});
addExpectedCycle(new LockEdge[] {e4, e5});
assertExpectedCycles();
}
@Test
public void testCyclesWithTwoTimesTwoPathsLarge() throws Exception {
LockEdge e1 = addEdge(1, 2);
LockEdge e2 = addEdge(2, 3);
LockEdge e3 = addEdge(3, 4);
LockEdge e3b = addEdge(3, 4, 2);
LockEdge e4 = addEdge(4, 5);
LockEdge e5 = addEdge(5, 6);
LockEdge e6 = addEdge(6, 1);
LockEdge e6b = addEdge(6, 1, 2);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e2, e3, e4, e5, e6});
addExpectedCycle(new LockEdge[] {e1, e2, e3b, e4, e5, e6});
addExpectedCycle(new LockEdge[] {e1, e2, e3b, e4, e5, e6b});
addExpectedCycle(new LockEdge[] {e1, e2, e3, e4, e5, e6b});
assertExpectedCycles();
}
@Test
public void testCyclesWithTwoTimesTwoPathsSmall() throws Exception {
LockEdge e1 = addEdge(1, 2);
LockEdge e2 = addEdge(2, 1);
LockEdge e1b = addEdge(1, 2, 2);
LockEdge e2b = addEdge(2, 1, 2);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e2});
addExpectedCycle(new LockEdge[] {e1b, e2});
addExpectedCycle(new LockEdge[] {e1, e2b});
addExpectedCycle(new LockEdge[] {e1b, e2b});
assertExpectedCycles();
}
@Test
public void testCyclesWithTwoAlternateWays() throws Exception {
LockEdge e1 = addEdge(1, 2);
LockEdge e2 = addEdge(1, 3);
LockEdge e3 = addEdge(2, 4);
LockEdge e4 = addEdge(3, 4);
LockEdge e5 = addEdge(4, 5);
LockEdge e6 = addEdge(4, 6);
LockEdge e7 = addEdge(5, 1);
LockEdge e8 = addEdge(6, 1);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e3, e5, e7});
addExpectedCycle(new LockEdge[] {e1, e3, e6, e8});
addExpectedCycle(new LockEdge[] {e2, e4, e5, e7});
addExpectedCycle(new LockEdge[] {e2, e4, e6, e8});
assertExpectedCycles();
}
@Test
public void testComplexCycles() throws Exception {
int a = 6;
int b = 3;
addEdge(1, 2);
LockEdge e2 = addEdge(2, b);
LockEdge e3 = addEdge(b, 4);
LockEdge e4 = addEdge(4, b);
LockEdge e5 = addEdge(b, 5);
LockEdge e6 = addEdge(5, 7);
LockEdge e7 = addEdge(7, 2);
LockEdge e8 = addEdge(2, a);
LockEdge e9 = addEdge(a, 5);
LockEdge e10 = addEdge(5, 8);
LockEdge e11 = addEdge(8, 9);
LockEdge e12 = addEdge(9, 5);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e3, e4});
addExpectedCycle(new LockEdge[] {e10, e11, e12});
addExpectedCycle(new LockEdge[] {e8, e9, e6, e7});
addExpectedCycle(new LockEdge[] {e2, e5, e6, e7});
assertExpectedCycles();
}
@Test
public void testLotsOfCycles() throws Exception {
int a = 1;
int b = 2;
int c = 3;
int d = 4;
LockEdge e1 = addEdge(a, b);
LockEdge e2 = addEdge(a, c);
LockEdge e3 = addEdge(a, d);
LockEdge e4 = addEdge(b, a);
LockEdge e5 = addEdge(b, c);
LockEdge e6 = addEdge(c, b);
LockEdge e7 = addEdge(c, d);
LockEdge e8 = addEdge(d, b);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e4});
addExpectedCycle(new LockEdge[] {e5, e6});
addExpectedCycle(new LockEdge[] {e2, e6, e4});
addExpectedCycle(new LockEdge[] {e3, e8, e4});
addExpectedCycle(new LockEdge[] {e5, e7, e8});
addExpectedCycle(new LockEdge[] {e2, e7, e8, e4});
assertExpectedCycles();
}
@Test
public void testComplexCycles2() throws Exception {
int a = 6;
int b = 3;
LockEdge e1 = addEdge(2, b);
LockEdge e2 = addEdge(b, 5);
LockEdge e3 = addEdge(5, 7);
LockEdge e4 = addEdge(7, 2);
LockEdge e5 = addEdge(2, a);
LockEdge e6 = addEdge(a, 5);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e5, e6, e3, e4 });
addExpectedCycle(new LockEdge[] {e1, e2, e3, e4 });
assertExpectedCycles();
}
@Test
public void testTwoSeparateCycles() throws Exception {
LockEdge e1 = addEdge(1, 2);
LockEdge e2 = addEdge(2, 1);
LockEdge e3 = addEdge(3, 4);
LockEdge e4 = addEdge(4, 3);
addEdge(4, 5);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e2});
addExpectedCycle(new LockEdge[] {e3, e4});
assertExpectedCycles();
}
@Test
public void testTwoConnectedCycles() throws Exception {
LockEdge e1 = addEdge(1, 2);
LockEdge e2 = addEdge(2, 1);
LockEdge e3 = addEdge(2, 3);
LockEdge e4 = addEdge(3, 2);
addEdge(2, 4);
addEdge(3, 4);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e2});
addExpectedCycle(new LockEdge[] {e3, e4});
assertExpectedCycles();
}
@Test
public void testDuplicatedEdges() throws Exception {
LockEdge e1 = addEdge(1, 2);
LockEdge e2 = addEdge(1, 2, 10);
LockEdge e3 = addEdge(2, 1);
addEdge(3, 4);
addEdge(4, 5);
addEdge(4, 5, 10);
mCycleDetector.analyzeLockNodes(mNodes);
addExpectedCycle(new LockEdge[] {e1, e3});
addExpectedCycle(new LockEdge[] {e2, e3});
assertExpectedCycles();
}
}