/** * Copyright (C) 2010 Hal Hildebrand. All rights reserved. * * This file is part of the Prime Mover Event Driven Simulation Framework. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * 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. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.hellblazer.primeMover.soot; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.Field; import java.util.ArrayList; import junit.framework.TestCase; import soot.G; import soot.Printer; import soot.Scene; import soot.SootClass; import soot.SootMethod; import com.hellblazer.primeMover.runtime.ContinuationFrame; import com.hellblazer.primeMover.runtime.Framework; /** * Test the transformation which implements the event continuations. * * @author <a href="mailto:hal.hildebrand@gmail.com">Hal Hildebrand</a> * */ public class TestContinuationTransformer extends TestCase { private static class MyMockController extends MockController { boolean saveFrame = false; boolean restoreFrame = false; ContinuationFrame frame; @Override public ContinuationFrame popFrame() { ContinuationFrame f = frame; frame = null; return f; } @Override public void pushFrame(ContinuationFrame frame) { this.frame = frame; } @Override public boolean restoreFrame() { return restoreFrame; } @Override public boolean saveFrame() { return saveFrame; } } public void testContinuations() throws Exception { G.reset(); SimulationTransform.setStandardClassPath(); SootClass continuationPrototype = getContinuationPrototypeImpl(); PrintStream out; out = System.out; out = new PrintStream(new ByteArrayOutputStream()); PrintWriter pw = new PrintWriter(out); // pw.println("Untransformed: "); // Printer.v().printTo(continuationPrototype, pw); pw.flush(); ArrayList<SootClass> generated = new ArrayList<SootClass>(); for (SootMethod method : continuationPrototype.getMethods()) { ContinuationTransformer transformer = new ContinuationTransformer( generated, true); transformer.transform(method.retrieveActiveBody()); } pw.println(); pw.println("Transformed: "); Printer.v().printTo(continuationPrototype, pw); pw.flush(); generated.add(continuationPrototype); Scene.v().loadNecessaryClasses(); generated.addAll(Scene.v().getApplicationClasses()); LocalLoader loader = new LocalLoader(generated); Thread.currentThread().setContextClassLoader(loader); /* verifyGenerated(loader, new ByteArrayInputStream( loader.classBits.get(ContinuationPrototypeImpl.class.getCanonicalName()))); */ Class<?> clazz = loader.loadClass(ContinuationPrototypeImpl.class.getCanonicalName()); assertNotSame(ContinuationPrototypeImpl.class, clazz); ContinuationPrototype prototype = (ContinuationPrototype) clazz.newInstance(); // Test transformed behavior with no controller present Framework.setController(null); assertEquals(2, prototype.zeroth()); assertEquals("AB", prototype.first()); assertEquals("B", prototype.second()); assertEquals("CD", prototype.third("C", "D")); assertEquals("ABBB", prototype.nested()); // simple save of frame MyMockController controller = new MyMockController(); controller.saveFrame = true; Framework.setController(controller); assertNotNull(Framework.queryController()); assertNull(prototype.first()); assertNotNull(controller.frame); Class<? extends ContinuationFrame> frameClass = controller.frame.getClass(); assertEquals(1, frameClass.getDeclaredFields().length); Field stringBuilder = frameClass.getDeclaredField("l_0"); StringBuilder builder = (StringBuilder) stringBuilder.get(controller.frame); assertNotNull(builder); // continue controller.saveFrame = false; controller.restoreFrame = true; assertEquals("AB", prototype.first()); assertNull(controller.frame); // test for saved argument state controller.saveFrame = true; controller.restoreFrame = false; controller.frame = null; assertNull(prototype.arguments(" ", "time ", "around")); assertNotNull(controller.frame); frameClass = controller.frame.getClass(); assertEquals(4, frameClass.getDeclaredFields().length); // continue controller.saveFrame = false; controller.restoreFrame = true; String result = prototype.arguments("!", "past ", "forgotten"); assertNotNull(result); assertEquals("first time around", result); } private SootClass getContinuationPrototypeImpl() { SootClass continuationPrototypeImpl = Scene.v().loadClassAndSupport(ContinuationPrototypeImpl.class.getCanonicalName()); for (SootMethod method : continuationPrototypeImpl.getMethods()) { method.retrieveActiveBody(); } return continuationPrototypeImpl; } }