//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.test.mc.basic;
import org.junit.Test;
import gov.nasa.jpf.ListenerAdapter;
import gov.nasa.jpf.jvm.bytecode.InvokeInstruction;
import gov.nasa.jpf.jvm.bytecode.PUTFIELD;
import gov.nasa.jpf.util.test.TestJPF;
import gov.nasa.jpf.vm.ChoiceGenerator;
import gov.nasa.jpf.vm.FieldInfo;
import gov.nasa.jpf.vm.Instruction;
import gov.nasa.jpf.vm.SystemState;
import gov.nasa.jpf.vm.ThreadInfo;
import gov.nasa.jpf.vm.VM;
import gov.nasa.jpf.vm.Verify;
/**
* simple test application to break transitions from listeners
*/
@SuppressWarnings("unused")
public class BreakTest extends TestJPF {
static final String LISTENER = "+listener=.test.mc.basic.BreakTestListener";
static class BreakListener extends ListenerAdapter {
public static int nCG; // braindead, just to check from outside
public BreakListener() {
nCG = 0;
}
@Override
public void choiceGeneratorSet (VM vm, ChoiceGenerator<?> newCG) {
System.out.println("CG set: " + newCG);
nCG++;
}
@Override
public void choiceGeneratorAdvanced (VM vm, ChoiceGenerator<?> currentCG) {
System.out.println("CG advanced: " + currentCG);
}
}
int data;
//--- test setIgnored
public static class FieldIgnorer extends BreakListener {
public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
SystemState ss = vm.getSystemState();
if (executedInsn instanceof PUTFIELD) { // break on field access
FieldInfo fi = ((PUTFIELD) executedInsn).getFieldInfo(null);
if (fi.getClassInfo().getName().endsWith(".BreakTest")) {
System.out.println("# ignoring after: " + executedInsn);
ss.setIgnored(true);
}
}
}
}
@Test
public void testSimpleIgnore () {
if (verifyNoPropertyViolation("+listener=.test.mc.basic.BreakTest$FieldIgnorer",
"+vm.max_transition_length=1000000")) {
int i = 42;
data = i; // we ignore here
fail("should never get here");
} else {
if (BreakListener.nCG != 1) { // that's really simplistic
fail("wrong number of CGs: " + BreakListener.nCG);
}
}
}
//--- testSimpleBreak
public static class FieldBreaker extends BreakListener {
public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
SystemState ss = vm.getSystemState();
if (executedInsn instanceof PUTFIELD) { // break on field access
FieldInfo fi = ((PUTFIELD) executedInsn).getFieldInfo(null);
if (fi.getClassInfo().getName().endsWith(".BreakTest")) {
System.out.println("# breaking after: " + executedInsn);
ti.breakTransition("breakTest");
}
}
}
}
@Test
public void testSimpleBreak () {
if (verifyNoPropertyViolation("+listener=.test.mc.basic.BreakTest$FieldBreaker",
"+vm.max_transition_length=1000000")) {
int i = 42;
data = i; // we break after that
i = 0;
} else {
if (BreakListener.nCG != 2) { // that's really simplistic
fail("wrong number of CGs: " + BreakListener.nCG);
}
}
}
//--- test CG chain break
public static class FooCallBreaker extends BreakListener {
public void instructionExecuted(VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn) {
SystemState ss = vm.getSystemState();
if (executedInsn instanceof InvokeInstruction) { // break on method call
InvokeInstruction call = (InvokeInstruction) executedInsn;
if ("foo()V".equals(call.getInvokedMethodName())) {
System.out.println("# breaking & pruning after: " + executedInsn);
System.out.println("# registered (ignored) CG: " + ss.getNextChoiceGenerator());
ti.breakTransition("breakTest"); // not required since we ignore
ss.setIgnored(true);
}
}
}
}
void foo () {
System.out.println("foo");
}
void bar () {
System.out.println("bar");
}
@Test
public void testDeepCGBreak () {
if (!isJPFRun()){
Verify.resetCounter(0);
}
if (verifyNoPropertyViolation("+listener=.test.mc.basic.BreakTest$FooCallBreaker")) {
if (Verify.getBoolean(false)) {
System.out.println("foo,bar branch");
foo(); // listener sets it ignored -> break
bar();
fail("should not get here");
} else {
Verify.incrementCounter(0);
System.out.println("bar,foo branch");
bar();
foo(); // listener sets it ignored -> break
fail("should not get here");
}
}
if (!isJPFRun()){
assert Verify.getCounter(0) == 1;
}
}
//--- test ignore after setting nextCG
public static class VerifyNextIntBreaker extends BreakListener {
public void choiceGeneratorRegistered(VM vm, ChoiceGenerator<?> nextCG, ThreadInfo ti, Instruction executedInsn) {
SystemState ss = vm.getSystemState();
ChoiceGenerator<?> cg = ss.getNextChoiceGenerator();
if (cg.getId().equals("verifyGetInt(II)")) {
System.out.println("# breaking & pruning after: " + ti.getPC());
System.out.println("# registered (ignored) CG: " + cg);
ss.setIgnored(true); // should reset the IntIntervalCG registered by the native getInt()
ti.breakTransition("breakTest"); // should have no effect
}
}
}
@Test
public void testIgnoreAfterCG () {
if (!isJPFRun()){
Verify.resetCounter(0);
}
if (verifyNoPropertyViolation("+listener=.test.mc.basic.BreakTest$VerifyNextIntBreaker")) {
if (Verify.getBoolean(false)){
System.out.println("true branch (should be first)");
int i = Verify.getInt(1, 2); // listener breaks & ignores post exec
fail("should never get here");
} else {
Verify.incrementCounter(0);
System.out.println("false branch");
}
}
if (!isJPFRun()){
assert Verify.getCounter(0) == 1;
}
}
}