ProgramState implements ProgramStateConstraints { public Optional<ProgramState> constrain(@Nullable SymbolicValue value, @Nullable Constraint constraint) { Optional<ProgramState> ps = this.constrainWithoutEquivalent(value, constraint); if (ps.isPresent()) { Constraint newConstraint = ps.get().getConstraint(value); Set<SymbolicValue> equivalentValues = getEquivalentValues(value); for (SymbolicValue equivalentValue : equivalentValues) { if (ps.isPresent()) { ps = ps.get().constrainWithoutEquivalent(equivalentValue, newConstraint); } else { break; } } } return ps; } private  ProgramState(
    ImmutableMap<Symbol, SymbolicValue> values,
    ImmutableMap<SymbolicValue, Constraint> constraints,
    ExpressionStack stack,
    ImmutableSet<Relation> relations,
    int counter); ImmutableMap<Symbol, SymbolicValue> values(); static ProgramState emptyState(); ProgramState newSymbolicValue(Symbol symbol, @Nullable Constraint constraint); ProgramState newFunctionSymbolicValue(Symbol symbol, FunctionTree functionTree); Optional<ProgramState> constrain(@Nullable SymbolicValue value, @Nullable Constraint constraint); @CheckForNull SymbolicValue getSymbolicValue(@Nullable Symbol symbol); @Override Constraint getConstraint(@Nullable SymbolicValue value); Constraint getConstraint(@Nullable Symbol symbol); ProgramState pushToStack(SymbolicValue value); ProgramState removeLastValue(); ProgramState clearStack(Tree element); void assertEmptyStack(Tree element); ProgramState execute(ExpressionTree expression); ProgramState withStack(ExpressionStack newStack); ProgramState assignment(Symbol variable); ProgramState assignment(Symbol variable, SymbolicValue value); Set<Relation> relations(); ProgramState addRelation(Relation relation); @Override boolean equals(Object o); @Override int hashCode(); SymbolicValue peekStack(); SymbolicValue peekStack(int n); ProgramState removeSymbols(Set<Symbol> symbolsToKeep); @Deprecated ExpressionStack getStack(); @Override String toString(); @Nullable SymbolicValue getSymbolicValue(IdentifierTree identifier, SymbolicExecution execution);  }
@Test public void constrain() throws Exception { state = state.newSymbolicValue(symbol1, null); SymbolicValue sv1 = state.getSymbolicValue(symbol1); SymbolicValue sv2 = state.getSymbolicValue(symbol2); assertThat(state.constrain(sv1, Constraint.FALSY).get().getConstraint(symbol1).isStricterOrEqualTo(Constraint.FALSY)).isTrue(); assertThat(sv2).isNull(); assertThat(state.constrain(sv2, Constraint.FALSY).get().getConstraint(symbol2)).isEqualTo(Constraint.ANY_VALUE); state = state.newSymbolicValue(symbol1, Constraint.NULL_OR_UNDEFINED); assertThat(state.constrain(state.getSymbolicValue(symbol1), Constraint.TRUTHY).isPresent()).isFalse(); state = state.newSymbolicValue(symbol2, null); state = state.constrain(state.getSymbolicValue(symbol2), Constraint.TRUTHY).get(); assertThat(state.constrain(state.getSymbolicValue(symbol2), Constraint.NULL).isPresent()).isFalse(); }