using Microsoft.Boogie.TestUtil; using Microsoft.Boogie; using Microsoft.Basetypes; using NUnit.Framework; using System; using System.Linq; namespace CoreTests { [TestFixture ()] public class DuplicatorTests : BoogieTestBase, IErrorSink { Duplicator d; public void Error(IToken tok, string msg) { Assert.Fail(msg); } [SetUp] public void Init() { d = new Duplicator(); } [Test()] public void BVConcatExpr() { var bv1_8 = new LiteralExpr(Token.NoToken, BigNum.FromInt(1), 8); var bv2_8 = new LiteralExpr(Token.NoToken, BigNum.FromInt(2), 8); var A = new BvConcatExpr(Token.NoToken, bv1_8, bv2_8); var B = d.Visit(A); // The duplicator should ensure we get new BVConcatExprs Assert.AreNotSame(A, B); } [Test()] public void BvExtractExpr() { var bv2_8 = new LiteralExpr(Token.NoToken, BigNum.FromInt(2), 8); var A = new BvExtractExpr(Token.NoToken, bv2_8, 6,0); var B = d.Visit(A); // The duplicator should ensure we get new BVExtractExprs Assert.AreNotSame(A, B); } [Test()] public void NaryExpr() { var bv1_8 = new LiteralExpr(Token.NoToken, BigNum.FromInt(1), 8); var bv2_8 = new LiteralExpr(Token.NoToken, BigNum.FromInt(2), 8); var A = NAryExpr.Eq (bv1_8, bv2_8); var B = d.Visit(A); Assert.AreNotSame(A, B); } [Test()] public void WholeProgram() { var p = new Program(); var t = new TypedIdent(Token.NoToken, "foo", Microsoft.Boogie.Type.Bool); var gv = new GlobalVariable(Token.NoToken, t); p.AddTopLevelDeclaration(gv); string metaDataString = "This is a test"; p.SetMetadata(0, metaDataString); // Now try to clone var p2 = (Program) d.Visit(p); // Check global is a copy int counter = 0; GlobalVariable gv2 = null; foreach (var g in p2.TopLevelDeclarations) { ++counter; Assert.IsInstanceOf(g); gv2 = g as GlobalVariable; } Assert.AreEqual(1, counter); Assert.AreNotSame(gv, gv2); Assert.AreEqual(metaDataString, p2.GetMetadata(0)); // Check Top level declarations list is duplicated properly var t2 = new TypedIdent(Token.NoToken, "bar", Microsoft.Boogie.Type.Bool); var gv3 = new GlobalVariable(Token.NoToken, t2); p2.AddTopLevelDeclaration(gv3); counter = 0; foreach (var g in p2.TopLevelDeclarations) { ++counter; Assert.IsInstanceOf(g); } Assert.AreEqual(2, counter); // The original program should still only have one global variable counter = 0; foreach (var g in p.TopLevelDeclarations) { ++counter; Assert.IsInstanceOf(g); Assert.AreSame(g, gv); } Assert.AreEqual(1, counter); // Change Metadata in p2, this shouldn't affect p string newMetaDataString = "Another test"; p2.SetMetadata(0, newMetaDataString); Assert.AreNotEqual(p2.GetMetadata(0), p.GetMetadata(0)); } [Test()] public void GotoTargets() { Program p = TestUtil.ProgramLoader.LoadProgramFrom(@" procedure main() { entry: assume true; goto thing1, thing2; thing1: assume true; assume true; goto entry, thing1; thing2: assume true; assume true; return; } "); var main = p.TopLevelDeclarations.OfType().Where(x => x.Name == "main").First(); // Access blocks via their labels of gotocmds var oldEntryBlock = ( main.Blocks[1].TransferCmd as GotoCmd ).labelTargets[0]; Assert.AreEqual("entry", oldEntryBlock.Label); var oldThing1Block = ( main.Blocks[1].TransferCmd as GotoCmd ).labelTargets[1]; Assert.AreEqual("thing1", oldThing1Block.Label); var oldThing2Block = ( main.Blocks[0].TransferCmd as GotoCmd ).labelTargets[1]; Assert.AreEqual("thing2", oldThing2Block.Label); // Now duplicate var newProgram = (Program) d.Visit(p); // First lets check blocks have been duplicated var newMain= newProgram.TopLevelDeclarations.OfType().Where(x => x.Name == "main").First(); var newEntryBlock = newMain.Blocks[0]; Assert.AreEqual("entry", newEntryBlock.Label); Assert.AreNotSame(newEntryBlock, oldEntryBlock); var newThing1Block = newMain.Blocks[1]; Assert.AreEqual("thing1", newThing1Block.Label); Assert.AreNotSame(newThing1Block, oldThing1Block); var newThing2Block = newMain.Blocks[2]; Assert.AreEqual("thing2", newThing2Block.Label); Assert.AreNotSame(newThing2Block, oldThing2Block); // Now let's examine the gotos and make sure they point to the duplicated blocks. var newEntryGotoCmd = newEntryBlock.TransferCmd as GotoCmd; var newthing1GotoCmd = newThing1Block.TransferCmd as GotoCmd; Assert.AreNotSame(newEntryGotoCmd.labelTargets[0], oldThing1Block); Assert.AreSame(newEntryGotoCmd.labelTargets[0], newThing1Block); Assert.AreNotSame(newEntryGotoCmd.labelTargets[1], oldThing2Block); Assert.AreSame(newEntryGotoCmd.labelTargets[1], newThing2Block); Assert.AreNotSame(newthing1GotoCmd.labelTargets[0], oldEntryBlock); Assert.AreSame(newthing1GotoCmd.labelTargets[0], newEntryBlock); Assert.AreNotSame(newthing1GotoCmd.labelTargets[1], oldThing1Block); Assert.AreSame(newthing1GotoCmd.labelTargets[1], newThing1Block); } [Test()] public void ImplementationProcedureResolving() { Program p = TestUtil.ProgramLoader.LoadProgramFrom(@" procedure main(a:int) returns (r:int); requires a > 0; ensures r > a; implementation main(a:int) returns (r:int) { r:= a + 1; } "); // Check resolved var oldMainImpl = p.TopLevelDeclarations.OfType().Where(i => i.Name == "main").First(); var oldMainProc = p.TopLevelDeclarations.OfType().Where(i => i.Name == "main").First(); Assert.AreSame(oldMainImpl.Proc, oldMainProc); // Now duplicate the program var newProgram = (Program) d.Visit(p); // Resolving doesn't seem to fix this. var rc = new ResolutionContext(this); newProgram.Resolve(rc); // Check resolved var newMainImpl = newProgram.TopLevelDeclarations.OfType().Where(i => i.Name == "main").First(); var newMainProc = newProgram.TopLevelDeclarations.OfType().Where(i => i.Name == "main").First(); Assert.AreSame(newMainImpl.Proc, newMainProc); } [Test()] public void CallCmdResolving() { Program p = TestUtil.ProgramLoader.LoadProgramFrom(@" procedure main() { var x:int; call x := foo(); call x := bar(); } procedure foo() returns(r:int) { r := 0; } procedure bar() returns(r:int); ensures r == 0; "); // Get hold of the procedures that will be used with the CallCmd var oldFoo = p.TopLevelDeclarations.OfType().Where(i => i.Name == "foo").First(); var oldBar = p.TopLevelDeclarations.OfType().Where(i => i.Name == "bar").First(); // Get the CallCmds to foo and bar var oldCmdsInMain = p.TopLevelDeclarations.OfType().Where(i => i.Name == "main").SelectMany(i => i.Blocks).SelectMany(b => b.Cmds); var oldCallToFoo = oldCmdsInMain.OfType().Where(c => c.callee == "foo").First(); var oldCallToBar = oldCmdsInMain.OfType().Where(c => c.callee == "bar").First(); // Check the Calls Assert.AreSame(oldCallToFoo.Proc, oldFoo); Assert.AreSame(oldCallToBar.Proc, oldBar); // Now duplicate the program and check that the calls are resolved correctly var newProgram = (Program) d.Visit(p); var foo = newProgram.TopLevelDeclarations.OfType().Where(i => i.Name == "foo").First(); var bar = newProgram.TopLevelDeclarations.OfType().Where(i => i.Name == "bar").First(); // Get the call to Foo var cmdsInMain = newProgram.TopLevelDeclarations.OfType().Where(i => i.Name == "main").SelectMany(i => i.Blocks).SelectMany(b => b.Cmds); var callToFoo = cmdsInMain.OfType().Where(c => c.callee == "foo").First(); var callToBar = cmdsInMain.OfType().Where(c => c.callee == "bar").First(); // Check the Calls Assert.AreNotSame(callToFoo.Proc, oldFoo); Assert.AreSame(callToFoo.Proc, foo); Assert.AreNotSame(callToBar.Proc, oldBar); Assert.AreSame(callToBar.Proc, bar); } } }