/*
* Copyright (C) 2021 Daniel Dietsch (dietsch@informatik.uni-freiburg.de)
* Copyright (C) 2022 Dominik Klumpp (klumpp@informatik.uni-freiburg.de)
* Copyright (C) 2021-2022 University of Freiburg
*
* This file is part of the ULTIMATE ModelCheckerUtils Library.
*
* The ULTIMATE ModelCheckerUtils Library library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ULTIMATE ModelCheckerUtils Library library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ULTIMATE ModelCheckerUtils Library. If not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you modify the ULTIMATE ModelCheckerUtils Library, or any covered work, by linking
* or combining it with Eclipse RCP (or a modified version of Eclipse RCP),
* containing parts covered by the terms of the Eclipse Public License, the
* licensors of the ULTIMATE ModelCheckerUtils Library library grant you additional permission
* to convey the resulting work.
*/
package de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.hoaretriple;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import de.uni_freiburg.informatik.ultimate.core.model.services.ILogger;
import de.uni_freiburg.informatik.ultimate.core.model.services.ILogger.LogLevel;
import de.uni_freiburg.informatik.ultimate.core.model.services.IUltimateServiceProvider;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.CfgSmtToolkit;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.ConcurrencyInformation;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.DefaultIcfgSymbolTable;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.ModifiableGlobalsTable;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.SmtFunctionsAndAxioms;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.BasicCallAction;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.BasicInternalAction;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.structure.IcfgEdgeFactory;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.TransFormulaBuilder;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.UnmodifiableTransFormula;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.transitions.UnmodifiableTransFormula.Infeasibility;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramConst;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramNonOldVar;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.IProgramVar;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramConst;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.cfg.variables.ProgramVarUtils;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.SmtParserUtils;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.BasicPredicateFactory;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.PredicateUnifier;
import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.scripttransfer.HistoryRecordingScript;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.IncrementalPlicationChecker.Validity;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.ManagedScript;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtSortUtils;
import de.uni_freiburg.informatik.ultimate.lib.smtlibutils.SmtUtils.SimplificationTechnique;
import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm;
import de.uni_freiburg.informatik.ultimate.logic.Logics;
import de.uni_freiburg.informatik.ultimate.logic.Script;
import de.uni_freiburg.informatik.ultimate.logic.Sort;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.TermVariable;
import de.uni_freiburg.informatik.ultimate.test.mocks.UltimateMocks;
import de.uni_freiburg.informatik.ultimate.util.datastructures.DataStructureUtils;
import de.uni_freiburg.informatik.ultimate.util.datastructures.SerialProvider;
import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation;
/**
*
* @author Daniel Dietsch (dietsch@informatik.uni-freiburg.de)
* @author Dominik Klumpp (klumpp@informatik.uni-freiburg.de)
*
*/
public abstract class AbstractHoareTripleCheckerTest {
private static final String PROCEDURE = AbstractHoareTripleCheckerTest.class.getSimpleName();
private static final String CALLER = "caller";
private static final String CALLEE = "callee";
protected IUltimateServiceProvider mServices;
protected Script mScript;
protected ManagedScript mMgdScript;
protected ILogger mLogger;
protected PredicateUnifier mPredicateUnifier;
protected CfgSmtToolkit mCsToolkit;
protected final DefaultIcfgSymbolTable mSymbolTable = new DefaultIcfgSymbolTable();
private IProgramConst c, d;
private IProgramNonOldVar x, y, z;
protected abstract IHoareTripleChecker getHtc();
@Before
public void setUp() {
mServices = UltimateMocks.createUltimateServiceProviderMock(LogLevel.DEBUG);
mScript = new HistoryRecordingScript(UltimateMocks.createZ3Script(LogLevel.INFO));
mLogger = mServices.getLoggingService().getLogger(AbstractHoareTripleCheckerTest.class);
mMgdScript = new ManagedScript(mServices, mScript);
mScript.setLogic(Logics.ALL);
c = constructConst("c", SmtSortUtils.getIntSort(mScript));
d = constructConst("d", SmtSortUtils.getIntSort(mScript));
x = constructVar("x", SmtSortUtils.getIntSort(mScript));
y = constructVar("y", SmtSortUtils.getIntSort(mScript));
z = constructVar("z", SmtSortUtils.getIntSort(mScript));
final BasicPredicateFactory predicateFactory = new BasicPredicateFactory(mServices, mMgdScript, mSymbolTable);
mPredicateUnifier = new PredicateUnifier(mLogger, mServices, mMgdScript, predicateFactory, mSymbolTable,
SimplificationTechnique.SIMPLIFY_DDA);
final var modifiable = new HashRelation();
modifiable.addPair(PROCEDURE, x);
modifiable.addPair(CALLER, x);
modifiable.addPair(CALLEE, x);
modifiable.addPair(CALLER, z);
final ModifiableGlobalsTable modGlobTab = new ModifiableGlobalsTable(modifiable);
final IcfgEdgeFactory icfgEdgeFactory = new IcfgEdgeFactory(new SerialProvider());
final ConcurrencyInformation ci =
new ConcurrencyInformation(Collections.emptyMap(), Collections.emptyMap(), Collections.emptySet());
final SmtFunctionsAndAxioms smtFunctionsAndAxioms = new SmtFunctionsAndAxioms(mMgdScript);
mCsToolkit = new CfgSmtToolkit(modGlobTab, mMgdScript, mSymbolTable, Collections.emptySet(),
Collections.emptyMap(), Collections.emptyMap(), icfgEdgeFactory, ci, smtFunctionsAndAxioms);
}
private void testInternal(final Validity validity, final Validity expected, final String pre,
final UnmodifiableTransFormula act, final String post) {
assert validity == Validity.VALID || validity == Validity.INVALID : "Triple must be either valid or invalid";
assert validity == expected || expected == Validity.UNKNOWN : "Inconsistent expected validity";
final IPredicate precond = pred(pre);
final IPredicate postcond = pred(post);
final IHoareTripleChecker htc = getHtc();
final Validity actual =
htc.checkInternal(precond, new BasicInternalAction(PROCEDURE, PROCEDURE, act), postcond);
Assert.assertEquals("Unexpected validity for " + validity + " Hoare triple:", expected, actual);
}
private void testCall(final Validity validity, final Validity expected, final String pre,
final UnmodifiableTransFormula act, final String post) {
assert validity == Validity.VALID || validity == Validity.INVALID : "Triple must be either valid or invalid";
assert validity == expected || expected == Validity.UNKNOWN : "Inconsistent expected validity";
final IPredicate precond = pred(pre);
final IPredicate postcond = pred(post);
final IHoareTripleChecker htc = getHtc();
final Validity actual = htc.checkCall(precond, new BasicCallAction(CALLER, CALLEE, act), postcond);
Assert.assertEquals("Unexpected validity for " + validity + " Hoare triple:", expected, actual);
}
/*
* ****************************************************************************************************************
* Code to parse formulas and terms.
* ****************************************************************************************************************
*/
private IProgramConst constructConst(final String name, final Sort sort) {
mScript.declareFun(name, new Sort[0], sort);
final IProgramConst constant = new ProgramConst(name, (ApplicationTerm) mScript.term(name), false);
mSymbolTable.add(constant);
return constant;
}
private IProgramNonOldVar constructVar(final String name, final Sort sort) {
final IProgramNonOldVar variable = ProgramVarUtils.constructGlobalProgramVarPair(name, sort, mMgdScript, null);
mSymbolTable.add(variable);
return variable;
}
private Term parseWithInOutVariables(final String syntax) {
final var inVars = suffixVars("_in");
final var outVars = suffixVars("_out");
return SmtParserUtils.parseWithVariables(syntax, mServices, mMgdScript,
DataStructureUtils.union(inVars, outVars));
}
private Term parseWithVariables(final String syntax) {
return SmtParserUtils.parseWithVariables(syntax, mServices, mMgdScript, mSymbolTable);
}
private Set suffixVars(final String suffix) {
return mSymbolTable.getGlobals().stream().map(
pv -> mScript.getTheory().createTermVariable(pv.getTermVariable().getName() + suffix, pv.getSort()))
.collect(Collectors.toSet());
}
private IPredicate pred(final String formula) {
return mPredicateUnifier.getOrConstructPredicate(parseWithVariables(formula));
}
private TermVariable outVar(final IProgramVar variable) {
return mScript.variable(variable.getTermVariable().getName() + "_out", variable.getSort());
}
private TermVariable inVar(final IProgramVar variable) {
return mScript.variable(variable.getTermVariable().getName() + "_in", variable.getSort());
}
private UnmodifiableTransFormula assumeTrue() {
// Build "assume true" statement
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(), true, Set.of(), true, null, true);
tfb.setFormula(mScript.term("true"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
return tfb.finishConstruction(mMgdScript);
}
/*
* ****************************************************************************************************************
* Actual tests.
* ****************************************************************************************************************
*/
@Test
public void disjointVarsButConst() {
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(), false, Set.of(c), true, null, true);
tfb.setFormula(parseWithInOutVariables("(>= c 0)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.VALID, disjointVarsButConstVerdict(), "true", tf, "(>= c 0)");
}
protected Validity disjointVarsButConstVerdict() {
return Validity.VALID;
}
@Test
public void disjointVarsButConstToFalse() {
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(), false, Set.of(c), true, null, true);
tfb.setFormula(parseWithInOutVariables("(>= c 0)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.VALID, disjointVarsButConstToFalseVerdict(), "(< c 0)", tf, "false");
}
protected Validity disjointVarsButConstToFalseVerdict() {
return Validity.VALID;
}
@Test
public void constsButDisjoint() {
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(), false, Set.of(d), true, null, true);
tfb.setFormula(parseWithInOutVariables("(>= d 0)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.INVALID, constsButDisjointVerdict(), "true", tf, "(>= c 0)");
}
protected Validity constsButDisjointVerdict() {
return Validity.INVALID;
}
@Test
public void constsButDisjointToFalse() {
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(), false, Set.of(d), true, null, true);
tfb.setFormula(parseWithInOutVariables("(>= d 0)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.INVALID, constsButDisjointToFalseVerdict(), "(<= c 0)", tf, "false");
}
protected Validity constsButDisjointToFalseVerdict() {
return Validity.INVALID;
}
@Test
public void constsPreservedInternal() {
final var tf = assumeTrue();
testInternal(Validity.VALID, constsPreservedInternalVerdict(), "(<= c 0)", tf, "(<= c 0)");
}
protected Validity constsPreservedInternalVerdict() {
return Validity.VALID;
}
@Test
public void constsWeakenedInternal() {
final var tf = assumeTrue();
testInternal(Validity.VALID, constsWeakenedInternalVerdict(), "(= c 0)", tf, "(<= c 0)");
}
protected Validity constsWeakenedInternalVerdict() {
return Validity.VALID;
}
@Test
public void preImplPostNoAssign() {
final var tfb =
new TransFormulaBuilder(Map.of(x, inVar(x)), Map.of(x, inVar(x)), false, Set.of(), true, null, true);
tfb.setFormula(parseWithInOutVariables("(= x_in 3)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.VALID, preImplPostNoAssignVerdict(), "(>= x 2)", tf, "(>= x 0)");
}
protected Validity preImplPostNoAssignVerdict() {
return Validity.VALID;
}
@Test
public void preImplPostButAssigns() {
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(x, outVar(x)), false, Set.of(), true, null, true);
tfb.setFormula(parseWithInOutVariables("(= x_out 3)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.INVALID, preImplPostButAssignsVerdict(), "(= x 0)", tf, "(<= x 0)");
}
protected Validity preImplPostButAssignsVerdict() {
return Validity.INVALID;
}
@Test
public void preImplPostAssignPreNotPost() {
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(x, outVar(x)), false, Set.of(), true, null, true);
tfb.setFormula(parseWithInOutVariables("(= x_out 3)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.VALID, preImplPostAssignPreNotPostVerdict(), "(and (= x 0) (= x y))", tf, "(<= y 0)");
}
protected Validity preImplPostAssignPreNotPostVerdict() {
return Validity.VALID;
}
@Test
public void preImplPostAssignPostNotPre() {
final var tfb = new TransFormulaBuilder(Map.of(), Map.of(x, outVar(x)), false, Set.of(), true, null, true);
tfb.setFormula(parseWithInOutVariables("(= x_out 3)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.VALID, preImplPostAssignPostNotPreVerdict(), "(= y 0)", tf, "(or (<= y 0) (= x 0))");
}
protected Validity preImplPostAssignPostNotPreVerdict() {
return Validity.VALID;
}
@Test
public void noAssignAndNoImpl() {
final var tfb =
new TransFormulaBuilder(Map.of(x, inVar(x)), Map.of(x, inVar(x)), true, Set.of(), true, null, true);
tfb.setFormula(parseWithInOutVariables("(= x_in 11)"));
tfb.setInfeasibility(Infeasibility.UNPROVEABLE);
final var tf = tfb.finishConstruction(mMgdScript);
testInternal(Validity.INVALID, noAssignAndNoImplVerdict(), "(>= x 2)", tf, "(<= x 10)");
}
protected Validity noAssignAndNoImplVerdict() {
return Validity.INVALID;
}
@Test
public void nonModifiableOldVar() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y,
PROCEDURE) : "Test requires y to be non-modifiable";
final var tf = assumeTrue();
// This Hoare triple is valid because y is not modifiable in the procedure.
testInternal(Validity.VALID, nonModifiableOldVarVerdict(), "(= y 42)", tf, "(= |old(y)| 42)");
}
protected Validity nonModifiableOldVarVerdict() {
return Validity.VALID;
}
@Test
public void nonModifiedOldVar() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, PROCEDURE) : "Test requires x to be modifiable";
final var tf = assumeTrue();
// This Hoare triple is invalid, because x is modifiable in the procedure.
testInternal(Validity.INVALID, nonModifiedOldVarVerdict(), "(= x 42)", tf, "(= |old(x)| 42)");
}
protected Validity nonModifiedOldVarVerdict() {
return Validity.INVALID;
}
@Test
public void differentNonModifiableOldVars() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y,
PROCEDURE) : "Test requires y to be non-modifiable";
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(z,
PROCEDURE) : "Test requires z to be non-modifiable";
final var tf = assumeTrue();
testInternal(Validity.INVALID, differentNonModifiableOldVarsVerdict(), "(= y 42)", tf, "(= |old(z)| 42)");
}
protected Validity differentNonModifiableOldVarsVerdict() {
return Validity.INVALID;
}
@Test
public void callNonModifiableOldNonOld() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y, CALLEE) : "Test requires y to be non-modifiable";
final var tf = assumeTrue();
testCall(Validity.VALID, callNonModifiableOldNonOldVerdict(), "(= y 0)", tf, "(= |old(y)| 0)");
}
protected Validity callNonModifiableOldNonOldVerdict() {
return Validity.VALID;
}
@Test
public void callModifiableOldNonOld() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, CALLEE) : "Test requires x to be modifiable";
final var tf = assumeTrue();
testCall(Validity.VALID, callModifiableOldNonOldVerdict(), "(= x 0)", tf, "(= |old(x)| 0)");
}
protected Validity callModifiableOldNonOldVerdict() {
return Validity.VALID;
}
@Test
public void callNonModifiableOld() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y, CALLER) : "Test requires y to be non-modifiable";
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y, CALLEE) : "Test requires y to be non-modifiable";
final var tf = assumeTrue();
testCall(Validity.VALID, callNonModifiableOldVerdict(), "(= |old(y)| 0)", tf, "(= |old(y)| 0)");
}
protected Validity callNonModifiableOldVerdict() {
return Validity.VALID;
}
@Test
public void callCallerModifiableOld() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(z, CALLER) : "Test requires z to be modifiable";
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y, CALLEE) : "Test requires z to be non-modifiable";
final var tf = assumeTrue();
testCall(Validity.INVALID, callCallerModifiableOldVerdict(), "(= |old(z)| 0)", tf, "(= |old(z)| 0)");
}
protected Validity callCallerModifiableOldVerdict() {
return Validity.INVALID;
}
@Test
public void callModifiableOld() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, CALLER) : "Test requires x to be modifiable";
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, CALLEE) : "Test requires x to be modifiable";
final var tf = assumeTrue();
testCall(Validity.INVALID, callModifiableOldVerdict(), "(= |old(x)| 0)", tf, "(= |old(x)| 0)");
}
protected Validity callModifiableOldVerdict() {
return Validity.INVALID;
}
@Test
public void constsPreservedCall() {
final var tf = assumeTrue();
testCall(Validity.VALID, constsPreservedCallVerdict(), "(<= c 0)", tf, "(<= c 0)");
}
protected Validity constsPreservedCallVerdict() {
return Validity.VALID;
}
@Test
public void constsWeakenedCall() {
final var tf = assumeTrue();
testCall(Validity.VALID, constsWeakenedCallVerdict(), "(= c 0)", tf, "(<= c 0)");
}
protected Validity constsWeakenedCallVerdict() {
return Validity.VALID;
}
@Test
public void pseudoTautologicalPostInternal() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y,
PROCEDURE) : "Test requires y to be unmodifiable";
final var tf = assumeTrue();
testInternal(Validity.VALID, pseudoTautologicalPostInternalVerdict(), "true", tf, "(= y |old(y)|)");
}
protected Validity pseudoTautologicalPostInternalVerdict() {
return Validity.VALID;
}
@Test
public void nonPseudoTautologicalPostInternal() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, PROCEDURE) : "Test requires x to be modifiable";
final var tf = assumeTrue();
testInternal(Validity.INVALID, nonPseudoTautologicalPostInternalVerdict(), "true", tf, "(= x |old(x)|)");
}
protected Validity nonPseudoTautologicalPostInternalVerdict() {
return Validity.INVALID;
}
@Test
public void pseudoTautologicalPostCall() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y, CALLEE) : "Test requires y to be unmodifiable";
final var tf = assumeTrue();
testCall(Validity.VALID, pseudoTautologicalPostCallVerdict(), "true", tf, "(= y |old(y)|)");
}
protected Validity pseudoTautologicalPostCallVerdict() {
return Validity.VALID;
}
@Test
public void nonPseudoTautologicalPostCall() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, CALLEE) : "Test requires x to be modifiable";
final var tf = assumeTrue();
testCall(Validity.VALID, nonPseudoTautologicalPostCallVerdict(), "true", tf, "(= x |old(x)|)");
}
protected Validity nonPseudoTautologicalPostCallVerdict() {
return Validity.VALID;
}
@Test
public void pseudoInconsistentPreInternal() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y,
PROCEDURE) : "Test requires y to be unmodifiable";
final var tf = assumeTrue();
testInternal(Validity.VALID, pseudoInconsistentPreInternalVerdict(), "(distinct y |old(y)|)", tf, "false");
}
protected Validity pseudoInconsistentPreInternalVerdict() {
return Validity.VALID;
}
@Test
public void nonPseudoInconsistentPreInternal() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, PROCEDURE) : "Test requires x to be modifiable";
final var tf = assumeTrue();
testInternal(Validity.INVALID, nonPseudoInconsistentPreInternalVerdict(), "(distinct x |old(x)|)", tf, "false");
}
protected Validity nonPseudoInconsistentPreInternalVerdict() {
return Validity.INVALID;
}
@Test
public void pseudoInconsistentPreCall() {
assert !mCsToolkit.getModifiableGlobalsTable().isModifiable(y, CALLER) : "Test requires y to be unmodifiable";
final var tf = assumeTrue();
testCall(Validity.VALID, pseudoInconsistentPreCallVerdict(), "(distinct y |old(y)|)", tf, "false");
}
protected Validity pseudoInconsistentPreCallVerdict() {
return Validity.VALID;
}
@Test
public void nonPseudoInconsistentPreCall() {
assert mCsToolkit.getModifiableGlobalsTable().isModifiable(x, CALLEE) : "Test requires x to be modifiable";
final var tf = assumeTrue();
testCall(Validity.INVALID, nonPseudoInconsistentPreCallVerdict(), "(distinct x |old(x)|)", tf, "false");
}
protected Validity nonPseudoInconsistentPreCallVerdict() {
return Validity.INVALID;
}
}