Repository: crawljax/crawljax
Issue: Max number of states is incorrect

Some crawls quit because the maximum number of states was reached, while it hasn't. 


Changed files:
core/src/test/java/com/crawljax/core/state/StateFlowGraphTest.java, core/src/main/java/com/crawljax/core/state/StateMachine.java, core/src/main/java/com/crawljax/core/state/StateFlowGraph.java, core/src/main/java/com/crawljax/plugins/savecrawlsession/SessionReader.java, core/src/test/java/com/crawljax/core/state/EventableTest.java

diff --git a/core/src/main/java/com/crawljax/core/state/StateFlowGraph.java b/core/src/main/java/com/crawljax/core/state/StateFlowGraph.java
index a9d3c2b7..a2291d7d 100644
--- a/core/src/main/java/com/crawljax/core/state/StateFlowGraph.java
+++ b/core/src/main/java/com/crawljax/core/state/StateFlowGraph.java
@@ -38,6 +38,7 @@ public class StateFlowGraph implements Serializable {
 	 * Thread-safety.
 	 */
 	private final AtomicInteger stateCounter = new AtomicInteger();
+	private final AtomicInteger nextStateNameCounter = new AtomicInteger();
 
 	private final StateVertex initialState;
 
@@ -53,6 +54,7 @@ public class StateFlowGraph implements Serializable {
 		sfg.addVertex(initialState);
 		stateCounter.incrementAndGet();
 		this.initialState = initialState;
+		LOG.debug("Initialized the stateflowgraph with an initial state");
 	}
 
 	/**
@@ -69,8 +71,8 @@ public class StateFlowGraph implements Serializable {
 	 * @return the clone if one is detected null otherwise.
 	 * @see org.jgrapht.Graph#addVertex(Object)
 	 */
-	public StateVertex addState(StateVertex stateVertix) {
-		return addState(stateVertix, true);
+	public StateVertex putIfAbsent(StateVertex stateVertix) {
+		return putIfAbsent(stateVertix, true);
 	}
 
 	/**
@@ -90,19 +92,20 @@ public class StateFlowGraph implements Serializable {
 	 * @see org.jgrapht.Graph#addVertex(Object)
 	 */
 	@GuardedBy("sfg")
-	public StateVertex addState(StateVertex stateVertix, boolean correctName) {
+	public StateVertex putIfAbsent(StateVertex stateVertix, boolean correctName) {
 		synchronized (sfg) {
-			if (!sfg.addVertex(stateVertix)) {
-				// Graph already contained the vertix
-				LOG.debug("Graph already contained vertex {}", stateVertix);
-				return this.getStateInGraph(stateVertix);
-			} else {
+			boolean added = sfg.addVertex(stateVertix);
+			if (added) {
 				int count = stateCounter.incrementAndGet();
 				LOG.debug("Number of states is now {}", count);
 				if (correctName) {
 					correctStateName(stateVertix);
 				}
 				return null;
+			} else {
+				// Graph already contained the vertix
+				LOG.debug("Graph already contained vertex {}", stateVertix);
+				return this.getStateInGraph(stateVertix);
 			}
 		}
 	}
@@ -369,8 +372,7 @@ public class StateFlowGraph implements Serializable {
 	 * @return State name the name of the state
 	 */
 	public String getNewStateName() {
-		stateCounter.getAndIncrement();
-		String state = makeStateName(stateCounter.get(), false);
+		String state = makeStateName(nextStateNameCounter.incrementAndGet(), false);
 		return state;
 	}
 
diff --git a/core/src/main/java/com/crawljax/core/state/StateMachine.java b/core/src/main/java/com/crawljax/core/state/StateMachine.java
index 8858d5eb..73c51c89 100644
--- a/core/src/main/java/com/crawljax/core/state/StateMachine.java
+++ b/core/src/main/java/com/crawljax/core/state/StateMachine.java
@@ -96,7 +96,7 @@ public class StateMachine {
 		        currentState.getName(), newState.getName());
 
 		// Add the state to the stateFlowGraph. Store the result
-		StateVertex cloneState = stateFlowGraph.addState(newState);
+		StateVertex cloneState = stateFlowGraph.putIfAbsent(newState);
 
 		// Is there a clone detected?
 		if (cloneState != null) {
diff --git a/core/src/main/java/com/crawljax/plugins/savecrawlsession/SessionReader.java b/core/src/main/java/com/crawljax/plugins/savecrawlsession/SessionReader.java
index 3a4e17af..a02c7d03 100644
--- a/core/src/main/java/com/crawljax/plugins/savecrawlsession/SessionReader.java
+++ b/core/src/main/java/com/crawljax/plugins/savecrawlsession/SessionReader.java
@@ -39,7 +39,7 @@ public class SessionReader {
 			if (sfg == null) {
 				sfg = new StateFlowGraph(state);
 			} else {
-				sfg.addState(state, false);
+				sfg.putIfAbsent(state, false);
 			}
 		}
 		for (Transition transition : savedCrawlSession.getTransitions()) {
diff --git a/core/src/test/java/com/crawljax/core/state/EventableTest.java b/core/src/test/java/com/crawljax/core/state/EventableTest.java
index 4e07ca80..7ceb5c83 100644
--- a/core/src/test/java/com/crawljax/core/state/EventableTest.java
+++ b/core/src/test/java/com/crawljax/core/state/EventableTest.java
@@ -108,7 +108,7 @@ public class EventableTest {
 		StateVertex s2 = new StateVertex("stateTarget", "dom2");
 		StateFlowGraph sfg = new StateFlowGraph(s1);
 
-		sfg.addState(s2);
+		sfg.putIfAbsent(s2);
 
 		Eventable e = new Eventable();
 
diff --git a/core/src/test/java/com/crawljax/core/state/StateFlowGraphTest.java b/core/src/test/java/com/crawljax/core/state/StateFlowGraphTest.java
index 987424fc..b3e6d56b 100644
--- a/core/src/test/java/com/crawljax/core/state/StateFlowGraphTest.java
+++ b/core/src/test/java/com/crawljax/core/state/StateFlowGraphTest.java
@@ -45,12 +45,12 @@ public class StateFlowGraphTest {
 	@Test
 	public void testSFG() throws Exception {
 		StateVertex DOUBLE = new StateVertex("index", "<table><div>index</div></table>");
-		assertTrue(graph.addState(state2) == null);
-		assertTrue(graph.addState(state3) == null);
-		assertTrue(graph.addState(state4) == null);
-		assertTrue(graph.addState(state5) == null);
+		assertTrue(graph.putIfAbsent(state2) == null);
+		assertTrue(graph.putIfAbsent(state3) == null);
+		assertTrue(graph.putIfAbsent(state4) == null);
+		assertTrue(graph.putIfAbsent(state5) == null);
 
-		assertFalse(graph.addState(DOUBLE) == null);
+		assertFalse(graph.putIfAbsent(DOUBLE) == null);
 
 		assertTrue(graph.addEdge(index, state2, new Eventable(new Identification(How.xpath,
 		        "/body/div[4]"), EventType.click)));
@@ -116,8 +116,8 @@ public class StateFlowGraphTest {
 		StateVertex state3clone2 =
 		        new StateVertex("STATE_THREE", "<table><div>state2</div></table>");
 
-		assertTrue(graph.addState(state2) == null);
-		assertTrue(graph.addState(state4) == null);
+		assertTrue(graph.putIfAbsent(state2) == null);
+		assertTrue(graph.putIfAbsent(state4) == null);
 		// assertFalse(graph.addState(state3));
 		assertTrue(graph.addEdge(index, state2, new Eventable(new Identification(How.xpath,
 		        "/body/div[4]"), EventType.click)));
@@ -149,7 +149,7 @@ public class StateFlowGraphTest {
 		                + "<body><div id='firstdiv' class='orange'>";
 
 		StateFlowGraph g = new StateFlowGraph(new StateVertex("", HTML1));
-		g.addState(new StateVertex("", HTML2));
+		g.putIfAbsent(new StateVertex("", HTML2));
 
 		assertEquals(206, g.getMeanStateStringSize());
 	}
@@ -161,8 +161,8 @@ public class StateFlowGraphTest {
 		Eventable c2 =
 		        new Eventable(new Identification(How.xpath, "/body/div[4]/div[2]"),
 		                EventType.click);
-		graph.addState(index);
-		graph.addState(state2);
+		graph.putIfAbsent(index);
+		graph.putIfAbsent(state2);
 
 		graph.addEdge(index, state2, c1);
 		graph.addEdge(index, state2, c2);
@@ -171,10 +171,10 @@ public class StateFlowGraphTest {
 
 	@Test
 	public void testAllPossiblePaths() {
-		graph.addState(state2);
-		graph.addState(state3);
-		graph.addState(state4);
-		graph.addState(state5);
+		graph.putIfAbsent(state2);
+		graph.putIfAbsent(state3);
+		graph.putIfAbsent(state4);
+		graph.putIfAbsent(state5);
 
 		graph.addEdge(index, state2, new Eventable(new Identification(How.xpath, "/index/2"),
 		        EventType.click));
@@ -218,10 +218,10 @@ public class StateFlowGraphTest {
 
 	@Test
 	public void largetTest() {
-		graph.addState(state2);
-		graph.addState(state3);
-		graph.addState(state4);
-		graph.addState(state5);
+		graph.putIfAbsent(state2);
+		graph.putIfAbsent(state3);
+		graph.putIfAbsent(state4);
+		graph.putIfAbsent(state5);
 
 		graph.addEdge(index, state2, new Eventable(new Identification(How.xpath, "/index/2"),
 		        EventType.click));
@@ -271,31 +271,31 @@ public class StateFlowGraphTest {
 
 	@Test
 	public void guidedCrawlingFlag() {
-		graph.addState(state2);
-		graph.addState(state3);
-		graph.addState(state4);
-		graph.addState(state5);
+		graph.putIfAbsent(state2);
+		graph.putIfAbsent(state3);
+		graph.putIfAbsent(state4);
+		graph.putIfAbsent(state5);
 
 		assertThat(graph, hasStates(5));
 
 		StateVertex state6 = new StateVertex("STATE_FIVE", "<table><div>state5</div></table>");
 		state6.setGuidedCrawling(false);
-		graph.addState(state6);
+		graph.putIfAbsent(state6);
 
 		assertThat(graph, hasStates(5));
 
 		state6.setGuidedCrawling(true);
 
-		graph.addState(state6);
+		graph.putIfAbsent(state6);
 		assertThat(graph, hasStates(6));
 
 	}
 
 	@Test
 	public void testEdges() throws Exception {
-		assertTrue(graph.addState(state2) == null);
-		assertTrue(graph.addState(state3) == null);
-		assertTrue(graph.addState(state4) == null);
+		assertTrue(graph.putIfAbsent(state2) == null);
+		assertTrue(graph.putIfAbsent(state3) == null);
+		assertTrue(graph.putIfAbsent(state4) == null);
 
 		Eventable e1 = new Eventable(new Identification(How.xpath, "/4/index"), EventType.click);
 
@@ -333,9 +333,9 @@ public class StateFlowGraphTest {
 		        new Eventable(new Identification(How.xpath, "/body/div[4]/div[6]"),
 		                EventType.click);
 
-		graph.addState(index);
-		graph.addState(state2);
-		graph.addState(state3);
+		graph.putIfAbsent(index);
+		graph.putIfAbsent(state2);
+		graph.putIfAbsent(state3);
 
 		graph.addEdge(index, state2, c1);
 		graph.addEdge(index, state2, c2);
@@ -356,7 +356,7 @@ public class StateFlowGraphTest {
 	@Test
 	public void whenStateAddedTheGraphCouterIsIncremented() {
 		assertThat(graph.getNumberOfStates(), is(1));
-		graph.addState(state2);
+		graph.putIfAbsent(state2);
 		assertThat(graph.getNumberOfStates(), is(2));
 	}