/** * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. * This file is licensed under the terms of the Modified BSD License. */ package abs.frontend.delta; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; import org.junit.Test; import abs.frontend.ast.ClassDecl; import abs.frontend.ast.DeltaDecl; import abs.frontend.ast.Model; import abs.frontend.ast.ModifyClassModifier; import abs.frontend.ast.ReturnStmt; public class OriginalCallTest extends DeltaTest { @Test public void originalCall() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "interface I {}" + "class C implements I { Unit m() {} }" + "delta D; uses M;" + "modifies class C { modifies Unit m() { original(); } }" + "delta D2; uses M;" + "modifies class C { modifies Unit m() { original(); } }" ); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); assertTrue(cls.getMethods().getNumChild() == 1); DeltaDecl delta1 = findDelta(model, "D"); assertTrue(delta1.getNumModuleModifier() == 1); assertTrue(((ModifyClassModifier) delta1.getModuleModifier(0)).getNumModifier() == 1); DeltaDecl delta2 = findDelta(model, "D2"); assertTrue(delta2.getNumModuleModifier() == 1); assertTrue(((ModifyClassModifier) delta2.getModuleModifier(0)).getNumModifier() == 1); /*Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(delta1,delta2))); assertTrue(delta1.getNumModuleModifier() == 2); assertTrue(delta2.getNumModuleModifier() == 2);*/ model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(delta1,delta2))); // there should be 3 methods now: the original one and those added by the two deltas assertEquals(3, cls.getMethods().getNumChild()); assertTrue(cls.getMethod(0).getMethodSig().getName().equals("m")); assertTrue(cls.getMethod(1).getMethodSig().getName().equals("m$ORIGIN_core")); assertTrue(cls.getMethod(2).getMethodSig().getName().equals("m$ORIGIN_D")); } @Test public void originalCall2() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "interface I {}" + "class C implements I { Unit m() {} }" + "delta D; uses M;" + "modifies class C { modifies Unit m() { original(); } }" + "delta D2; uses M;" + "modifies class C { modifies Unit m() { original(); } }" ); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); assertTrue(cls.getMethods().getNumChild() == 1); DeltaDecl delta1 = findDelta(model, "D"); assertTrue(delta1.getNumModuleModifier() == 1); assertTrue(((ModifyClassModifier) delta1.getModuleModifier(0)).getNumModifier() == 1); DeltaDecl delta2 = findDelta(model, "D2"); assertTrue(delta2.getNumModuleModifier() == 1); assertTrue(((ModifyClassModifier) delta2.getModuleModifier(0)).getNumModifier() == 1); /*Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(delta1,delta2))); assertTrue(delta1.getNumModuleModifier() == 2); assertTrue(delta2.getNumModuleModifier() == 2);*/ model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(delta1,delta2))); // there should be 3 methods now: the original one and those added by the two deltas assertEquals(3, cls.getMethods().getNumChild()); assertTrue(cls.getMethod(0).getMethodSig().getName().equals("m")); assertTrue(cls.getMethod(1).getMethodSig().getName().equals("m$ORIGIN_core")); assertTrue(cls.getMethod(2).getMethodSig().getName().equals("m$ORIGIN_D")); } @Test public void originalCall3() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "interface I {}" + "class C implements I { Int one() { return 1; } }" + "delta D; uses M;" + "modifies class C { modifies Int one() { Int x = original(); return x + 1; } }" ); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); assertEquals(1, cls.getMethods().getNumChild()); DeltaDecl delta1 = findDelta(model, "D"); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(delta1))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(delta1))); assertEquals(2, cls.getMethods().getNumChild()); assertTrue(cls.getMethod(0).getMethodSig().getName().equals("one")); // make sure method has the right body assertTrue(cls.getMethod(0).getBlock().getStmt(1) instanceof ReturnStmt); assertTrue(cls.getMethod(1).getMethodSig().getName().equals("one$ORIGIN_core")); // make sure method has the right body assertTrue(cls.getMethod(1).getBlock().getStmt(0) instanceof ReturnStmt); } @Test public void oneDeltaMultipleCalls() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "interface I {}" + "class C implements I { Unit m() {} Unit n() {} Unit p() {} }" + "delta D;uses M;" + "modifies class C {" + "modifies Unit m() { original(); }" + "modifies Unit n() { original(); }" + "modifies Unit p() { original(); }" + "}" ); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); DeltaDecl delta = findDelta(model, "D"); assertEquals(1, delta.getNumModuleModifier()); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(delta))); assertEquals(6, cls.getMethods().getNumChild()); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(delta))); //assertEquals(4, delta.getNumModuleModifier()); } @Test public void multipleCallsToSameMethod() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "interface I {}" + "class C implements I { Unit m() {} }" + "delta D;" + "modifies class M.C {" + "modifies Unit m() { original(); original(); }" + "}" ); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); DeltaDecl delta = findDelta(model, "D"); assertEquals(1, delta.getNumModuleModifier()); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(delta))); assertEquals(2, cls.getMethods().getNumChild()); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(delta))); //assertEquals(delta.getModuleModifiers().toString(),2, delta.getNumModuleModifier()); } @Test public void targetedAndUntargetedOriginalCall() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "class C { Unit m() {} }" + "delta D1; " + "uses M;" + "modifies class C { adds Unit n() {} }" + "delta D2; " + "uses M;" + "modifies class C { modifies Unit m() { original(); core.original(); } }" + "delta D3; " + "uses M;" + "modifies class C { modifies Unit n() { original(); D1.original(); } }" ); DeltaDecl d1 = findDelta(model, "D1"); DeltaDecl d2 = findDelta(model, "D2"); DeltaDecl d3 = findDelta(model, "D3"); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2,d3))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2,d3))); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); assertEquals(cls.getMethods().toString(), 4, cls.getMethods().getNumChild()); assertTrue(cls.getMethod(0).getMethodSig().getName().equals("m")); assertTrue(cls.getMethod(1).getMethodSig().getName().equals("n")); assertTrue(cls.getMethod(2).getMethodSig().getName().equals("m$ORIGIN_core")); assertTrue(cls.getMethod(3).getMethodSig().getName().equals("n$ORIGIN_D1")); } @Test public void targetedOriginalCall() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "class C { Unit m() {} }" + "delta D1;" + "uses M;" + "modifies class C { modifies Unit m() { core.original(); } }" + "adds class C2 { }" + "delta D2;" + "modifies class M.C { modifies Unit m() { D1.original(); } }" ); DeltaDecl d1 = findDelta(model, "D1"); DeltaDecl d2 = findDelta(model, "D2"); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2))); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); assertEquals(cls.getMethods().toString(), 3, cls.getMethods().getNumChild()); assertTrue(cls.getMethod(0).getMethodSig().getName().equals("m")); assertTrue(cls.getMethod(1).getMethodSig().getName().equals("m$ORIGIN_core")); assertTrue(cls.getMethod(2).getMethodSig().getName().equals("m$ORIGIN_D1")); } @Test public void multipleTargetedOriginalCalls() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "class C { }" + "delta D1;" + "uses M;" + "modifies class C { adds Unit m() {} }" + "delta D2;uses M;" + "modifies class C { modifies Unit m() { D1.original(); } }" + "delta D3;uses M;" + "modifies class C { modifies Unit m() { D1.original(); } }" ); DeltaDecl d1 = findDelta(model, "D1"); DeltaDecl d2 = findDelta(model, "D2"); DeltaDecl d3 = findDelta(model, "D3"); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2,d3))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2,d3))); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); assertEquals(cls.getMethods().toString(), 2, cls.getMethods().getNumChild()); assertTrue(cls.getMethod(0).getMethodSig().getName().equals("m")); assertTrue(cls.getMethod(1).getMethodSig().getName().equals("m$ORIGIN_D1")); } @Test public void multipleTargetedOriginalCalls2() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "class C { }" + "delta D1;" + "uses M;" + "modifies class C { adds Unit m() {} }" + "delta D2;uses M;" + "modifies class C { modifies Unit m() { D1.original(); } }" + "delta D3;uses M;" + "modifies class C { modifies Unit m() { D1.original(); } }" + "delta D4;uses M;" + "modifies class C { modifies Unit m() { D2.original(); } }" ); DeltaDecl d1 = findDelta(model, "D1"); DeltaDecl d2 = findDelta(model, "D2"); DeltaDecl d3 = findDelta(model, "D3"); DeltaDecl d4 = findDelta(model, "D4"); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2,d3))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(d1,d2,d3,d4))); ClassDecl cls = (ClassDecl) findDecl(model, "M", "C"); assertEquals(cls.getMethods().toString(), 3, cls.getMethods().getNumChild()); assertTrue(cls.getMethod(0).getMethodSig().getName().equals("m")); assertTrue(cls.getMethod(1).getMethodSig().getName().equals("m$ORIGIN_D1")); assertTrue(cls.getMethod(2).getMethodSig().getName().equals("m$ORIGIN_D2")); } @Test(expected=DeltaModellingException.class) public void originalNotFound() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "class C { }" + "delta D1;" + "modifies class C { modifies Unit m() { original(); } }" ); DeltaDecl d1 = findDelta(model, "D1"); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(d1))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(d1))); } @Test(expected=DeltaModellingException.class) public void targetedOriginalNotFound() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "class C { }" + "delta D1;" + "uses M;" + "modifies class C { modifies Unit m() { core.original(); } }" ); DeltaDecl d1 = findDelta(model, "D1"); //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(d1))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(d1))); } @Test public void targetedDeltaNotYetApplied() throws DeltaModellingException { Model model = assertParseOk( "module M;" + "class C { Unit m() {} }" + "delta D1;" + "uses M;" + "modifies class C { modifies Unit m() { core.original(); } }" + "delta D2;" + "uses M;" + "modifies class C { modifies Unit m() { D1.original(); } }" ); DeltaDecl d1 = findDelta(model, "D1"); DeltaDecl d2 = findDelta(model, "D2"); try { // applying deltas in wrong order (D2 then D1) should throw an exception // because D2 has a targeted original call to a method in D1 //Model.resolveOriginalCalls(new ArrayList<DeltaDecl>(Arrays.asList(d2,d1))); model.applyDeltas(new ArrayList<DeltaDecl>(Arrays.asList(d2,d1))); fail("expected a DeltaModellingException"); } catch (DeltaModellingException e) { assertThat(e.getMessage(), containsString("has not yet been applied")); } } }