/*******************************************************************************
 * Copyright (c) 2014 Johannes Lerch.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Johannes Lerch - initial API and implementation
 ******************************************************************************/
package heros;

import org.junit.Before;
import org.junit.Test;

import static heros.TestHelper.*;

public class IFDSSolverTest {

	private TestHelper helper;

	@Before
	public void before() {
		helper = new TestHelper();
	}
	
	@Test
	public void test() {
		helper.method("bar", 
				startPoints("a"),
				normalStmt("a").succ("b", flow("0", "x")),
				normalStmt("b").succ("c", flow("x", "x")),
				callSite("c").calls("foo", flow("x", "y")).retSite("f", flow("x", "x")));
		
		helper.method("foo",
				startPoints("d"),
				normalStmt("d").succ("e", flow("y", "y", "z")),
				exitStmt("e").returns(over("c"), to("f"), flow("z", "u"), flow("y")));
		
		helper.runSolver(false, "a");
	}
	
	@Test
	public void reuseSummary() {
		helper.method("foo", 
				startPoints("a"),
				callSite("a").calls("bar", flow("0", "x")).retSite("b", flow("0", "y")),
				callSite("b").calls("bar", flow("y", "x")).retSite("c", flow("y")),
				normalStmt("c").succ("c0", flow("w", "0")));
		
		helper.method("bar",
				startPoints("d"),
				normalStmt("d").succ("e", flow("x", "z")),
				exitStmt("e").returns(over("a"), to("b"), flow("z", "y"))
							  .returns(over("b"), to("c"), flow("z", "w")));
		
		helper.runSolver(false, "a");
	}
	
	@Test
	public void branch() {
		helper.method("foo",
				startPoints("a"),
				normalStmt("a").succ("b1", flow("0", "x")).succ("b2", flow("0", "x")),
				normalStmt("b1").succ("c", flow("x", "x", "y")),
				normalStmt("b2").succ("c", flow("x", "x")),
				normalStmt("c").succ("d", flow("x", "z"), flow("y", "w")),
				normalStmt("d").succ("e", flow("z"), flow("w")));
		
		helper.runSolver(false, "a");
	}
	
	@Test
	public void unbalancedReturn() {
		helper.method("foo",
				startPoints("a"),
				normalStmt("a").succ("b", flow("0", "1")),
				exitStmt("b").returns(over("x"),  to("y"), flow("1", "1")));
		
		helper.method("bar", 
				startPoints("unused"),
				normalStmt("y").succ("z", flow("1", "2")));
		
		helper.runSolver(true, "a");
	}
	
	@Test
	public void artificalReturnEdgeForNoCallersCase() {
		helper.method("foo",
				startPoints("a"),
				normalStmt("a").succ("b", flow("0", "1")),
				exitStmt("b").returns(null, null, flow("1", "1")));
		
		helper.runSolver(true, "a");
	}
}

@@ -1752,32 +1752,627 @@
 %22);%0A%09%7D%0A%09%0A%09@Test%0A
+%09public void reuseSummaryForRecursiveCall() %7B%0A%09%09helper.method(%22foo%22,%0A%09%09%09%09startPoints(%22a%22),%0A%09%09%09%09callSite(%22a%22).calls(%22bar%22, flow(%220%22, %221%22)).retSite(%22b%22, flow(%220%22)),%0A%09%09%09%09normalStmt(%22b%22).succ(%22c%22, flow(%222%22, %223%22)));%0A%09%09%0A%09%09helper.method(%22bar%22,%0A%09%09%09%09startPoints(%22g%22),%0A%09%09%09%09normalStmt(%22g%22).succ(%22h%22, flow(%221%22, %221%22)).succ(%22i%22, flow(%221%22, %221%22)),%0A%09%09%09%09callSite(%22i%22).calls(%22bar%22, flow(%221%22, %221%22)).retSite(%22h%22, flow(%221%22)),%0A%09%09%09%09exitStmt(%22h%22).returns(over(%22a%22), to(%22b%22), flow(%221%22), flow(%222%22 ,%222%22))%0A%09%09%09%09%09%09%09.returns(over(%22i%22), to(%22h%22), flow(%221%22,%222%22), flow(%222%22, %222%22)));%0A%09%09%09%09%0A%09%09helper.runSolver(false, %22a%22);%0A%09%7D%0A%09%0A%09@Test%0A
 %09public void bra

test case for reusing a summary on caller side