/* * SonarQube Java * Copyright (C) 2012-2016 SonarSource SA * mailto:contact AT sonarsource DOT com * * This program 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. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.java.se.symbolicvalues; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.junit.BeforeClass; import org.junit.Test; import org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static org.sonar.java.se.symbolicvalues.RelationState.FULFILLED; import static org.sonar.java.se.symbolicvalues.RelationState.UNDETERMINED; import static org.sonar.java.se.symbolicvalues.RelationState.UNFULFILLED; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.EQUAL; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.GREATER_THAN; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.GREATER_THAN_OR_EQUAL; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.LESS_THAN; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.LESS_THAN_OR_EQUAL; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.METHOD_EQUALS; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.NOT_EQUAL; import static org.sonar.java.se.symbolicvalues.RelationalSymbolicValue.Kind.NOT_METHOD_EQUALS; public class BinaryRelationsTest { private static int NUMBER_OF_VALUES = 5; private static SymbolicValue[] values = new SymbolicValue[NUMBER_OF_VALUES]; private static SymbolicValue SVa; private static SymbolicValue SVb; private static SymbolicValue SVc; @BeforeClass public static void initialize() { for (int i = 0; i < NUMBER_OF_VALUES; i++) { values[i] = new SymbolicValue(i); } SVa = values[0]; SVb = values[1]; SVc = values[2]; } @Test public void testEqual() { verifyEqualResolution(relationsWithOneValue(EQUAL)); } private List<BinaryRelation> relationsWithOneValue(Kind kind) { List<BinaryRelation> constraints = new ArrayList<>(); for (int i = 1; i < values.length; i++) { constraints.add(relation(kind, SVa, values[i])); } return constraints; } @Test public void testEqualChained() { verifyEqualResolution(relationsBetweenValue(EQUAL)); } private List<BinaryRelation> relationsBetweenValue(Kind kind) { List<BinaryRelation> constraints = new ArrayList<>(); for (int i = 1; i < values.length; i++) { constraints.add(relation(kind, values[i-1], values[i])); } return constraints; } private void verifyEqualResolution(List<BinaryRelation> constraints) { for (int i = 0; i < NUMBER_OF_VALUES; i++) { for (int j = 0; j < NUMBER_OF_VALUES; j++) { if (i != j) { BinaryRelation equalRelation = relation(EQUAL, values[i], values[j]); assertThat(equalRelation.resolveState(constraints)).as(equalRelation.toString()).isEqualTo(FULFILLED); BinaryRelation notEqualRelation = relation(NOT_EQUAL, values[i], values[j]); assertThat(notEqualRelation.resolveState(constraints)).as(notEqualRelation.toString()).isEqualTo(UNFULFILLED); } } } } @Test public void testNotEqual() { List<BinaryRelation> constraints = relationsWithOneValue(NOT_EQUAL); for (int i = 0; i < NUMBER_OF_VALUES; i++) { for (int j = 0; j < NUMBER_OF_VALUES; j++) { if (i != j) { BinaryRelation notEqualRelation = relation(NOT_EQUAL, values[i], values[j]); RelationState notEqualResult = notEqualRelation.resolveState(constraints); BinaryRelation equalRelation = relation(EQUAL, values[i], values[j]); RelationState equalResult = equalRelation.resolveState(constraints); if (i == 0 || j == 0) { assertThat(notEqualResult).as(notEqualRelation.toString()).isEqualTo(FULFILLED); assertThat(equalResult).as(equalRelation.toString()).isEqualTo(UNFULFILLED); } else { assertThat(notEqualResult).as(notEqualRelation.toString()).isEqualTo(UNDETERMINED); assertThat(equalResult).as(equalRelation.toString()).isEqualTo(UNDETERMINED); } } } } } @Test public void testNotEqualChained() { List<BinaryRelation> constraints = relationsBetweenValue(NOT_EQUAL); for (int i = 0; i < NUMBER_OF_VALUES; i++) { for (int j = 0; j < NUMBER_OF_VALUES; j++) { if (i != j) { BinaryRelation notEqualRelation = relation(NOT_EQUAL, values[i], values[j]); RelationState notEqualResult = notEqualRelation.resolveState(constraints); BinaryRelation equalRelation = relation(EQUAL, values[i], values[j]); RelationState equalResult = equalRelation.resolveState(constraints); if (Math.abs(j - i) == 1) { assertThat(notEqualResult).as(notEqualRelation.toString()).isEqualTo(FULFILLED); assertThat(equalResult).as(equalRelation.toString()).isEqualTo(UNFULFILLED); } else { assertThat(notEqualResult).as(notEqualRelation.toString()).isEqualTo(UNDETERMINED); assertThat(equalResult).as(equalRelation.toString()).isEqualTo(UNDETERMINED); } } } } } @Test public void a_equal_b_and_b_notEqual_c_implies_a_notEqual_c() { BinaryRelation r1 = relation(EQUAL, SVa, SVb); BinaryRelation r2 = relation(NOT_EQUAL, SVb, SVc); BinaryRelation r3 = relation(NOT_EQUAL, SVa, SVc); assertRelationHasState(r3, ImmutableList.of(r1, r2), FULFILLED); } @Test public void a_equal_b_and_b_equal_c_implies_not_a_notEqual_c() { checkImplies(EQUAL, EQUAL, NOT_EQUAL, UNFULFILLED); } @Test public void a_equal_b_and_a_equal_c_implies_b_equal_c() { checkImplies(EQUAL, EQUAL, EQUAL, FULFILLED); } private void checkImplies(Kind rel1, Kind rel2, Kind implied, RelationState expect) { BinaryRelation r1 = relation(rel1, SVa, SVb); BinaryRelation r2 = relation(rel2, SVa, SVc); assertRelationHasState(relation(implied, SVa, SVb), ImmutableList.of(r1, r2), expect); } @Test public void loopRelations() { List<BinaryRelation> knownRelations = ImmutableList.of( relation(NOT_EQUAL, SVa, SVb), relation(NOT_EQUAL, SVb, SVc), relation(NOT_EQUAL, SVc, values[3])); BinaryRelation checked = relation(NOT_EQUAL, SVa, values[3]); assertRelationHasState(checked, knownRelations, UNDETERMINED); } @Test public void reversedTransitive() { List<BinaryRelation> knownRelations = ImmutableList.of( relation(EQUAL, SVa, SVb), // a==b relation(EQUAL, SVa, SVc), // a==c relation(EQUAL, SVa, values[3]));// a==d BinaryRelation checked = relation(EQUAL, SVb, values[3]); // b==d? assertRelationHasState(checked, knownRelations, FULFILLED); } @Test public void transitiveA() throws Exception { List<BinaryRelation> knownRelations = ImmutableList.of( relation(EQUAL, SVa, SVb), // a==b relation(NOT_EQUAL, SVb, SVc));// b!=c BinaryRelation checked = relation(NOT_EQUAL, SVa, SVc); // a!=c? assertRelationHasState(checked, knownRelations, FULFILLED); } @Test public void transitiveB() { List<BinaryRelation> knownRelations = ImmutableList.of( relation(EQUAL, SVa, SVb), // a==b relation(NOT_EQUAL, SVc, SVb));// c!=b BinaryRelation checked = relation(NOT_EQUAL, SVa, SVc); // a!=c? assertRelationHasState(checked, knownRelations, FULFILLED); } @Test public void transitiveC() { List<BinaryRelation> knownRelations = ImmutableList.of( relation(EQUAL, SVa, SVb), // a==b relation(NOT_EQUAL, SVb, SVc));// b!=c BinaryRelation checked = relation(EQUAL, SVa, SVc); // a==c? assertRelationHasState(checked, knownRelations, UNFULFILLED); } @Test public void transitiveD() { List<BinaryRelation> knownRelations = ImmutableList.of( relation(EQUAL, SVa, SVb), // a==b relation(NOT_EQUAL, SVc, SVb));// c!=b BinaryRelation checked = relation(EQUAL, SVa, SVc); // a==c? assertRelationHasState(checked, knownRelations, UNFULFILLED); } private void assertRelationHasState(BinaryRelation checkedRelation, List<BinaryRelation> knownRelations, RelationState expectedState) { RelationState result = checkedRelation.resolveState(knownRelations); assertThat(result).as(checkedRelation.toString()).isEqualTo(expectedState); } @Test public void testInverse() { for (Kind kind : Kind.values()) { checkInverse(kind); } } private void checkInverse(Kind kind) { try { BinaryRelation relation = relation(kind, SVa, SVb); BinaryRelation inverseOfInverse = relation.inverse().inverse(); assertThat(relation.kind).isEqualTo(inverseOfInverse.kind); assertThat(relation.leftOp).isEqualTo(inverseOfInverse.leftOp); assertThat(relation.rightOp).isEqualTo(inverseOfInverse.rightOp); } catch (Exception e) { fail(e.getMessage()); } } @Test public void testSymmetric() { for (Kind kind : Kind.values()) { checkSymmetric(kind); } } private void checkSymmetric(Kind kind) { try { BinaryRelation relation = relation(kind, SVa, SVb); BinaryRelation symmetricOfSymmetric = relation.symmetric().symmetric(); assertThat(relation.kind).isEqualTo(symmetricOfSymmetric.kind); assertThat(relation.leftOp).isEqualTo(symmetricOfSymmetric.leftOp); assertThat(relation.rightOp).isEqualTo(symmetricOfSymmetric.rightOp); } catch (Exception e) { fail(e.getMessage()); } } @Test public void operandInRelationWithItself() throws Exception { RelationState[] expected = {FULFILLED, UNFULFILLED, UNFULFILLED, FULFILLED, UNFULFILLED, FULFILLED, FULFILLED, UNFULFILLED}; for (Kind kind : Kind.values()) { BinaryRelation relation = relation(kind, SVa, SVa); assertRelationHasState(relation, Collections.<BinaryRelation>emptyList(), expected[kind.ordinal()]); } } private static BinaryRelation relation(Kind kind, SymbolicValue a, SymbolicValue b) { RelationalSymbolicValue value = new RelationalSymbolicValue(-1, kind); value.computedFrom(Lists.newArrayList(b, a)); return value.binaryRelation(); } private void checkTransitive(BinaryRelation hypothesis1, BinaryRelation hypothesis2, BinaryRelation checked, RelationState expected) { List<BinaryRelation> hypotheses = ImmutableList.of(hypothesis1, hypothesis2); RelationState actual = checked.resolveState(hypotheses); assertThat(actual).as(hypothesis1.toString() + " && " + hypothesis2.toString() + " => " + checked.toString()).isEqualTo(expected); } @Test public void testEqualImplies() { checkImplies(EQUAL, new RelationState[]{FULFILLED, UNFULFILLED, UNFULFILLED, FULFILLED, UNFULFILLED, FULFILLED, FULFILLED, UNFULFILLED}); } @Test public void testNotEqualImplies() { checkImplies(NOT_EQUAL, new RelationState[]{UNFULFILLED, FULFILLED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNDETERMINED}); } @Test public void testMethodEqualsImplies() { checkImplies(METHOD_EQUALS, new RelationState[]{UNDETERMINED, UNDETERMINED, UNFULFILLED, FULFILLED, UNFULFILLED, FULFILLED, FULFILLED, UNFULFILLED}); } @Test public void testMethodNotEqualsImplies() { checkImplies(NOT_METHOD_EQUALS, new RelationState[]{UNFULFILLED, FULFILLED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNFULFILLED, FULFILLED}); } @Test public void testGreaterThanImplies() { checkImplies(GREATER_THAN, EQUAL, UNFULFILLED, UNFULFILLED); checkImplies(GREATER_THAN, NOT_EQUAL, FULFILLED, FULFILLED); checkImplies(GREATER_THAN, GREATER_THAN, FULFILLED, UNFULFILLED); checkImplies(GREATER_THAN, GREATER_THAN_OR_EQUAL, FULFILLED, UNFULFILLED); checkImplies(GREATER_THAN, LESS_THAN, UNFULFILLED, FULFILLED); checkImplies(GREATER_THAN, LESS_THAN_OR_EQUAL, UNFULFILLED, FULFILLED); checkImplies(GREATER_THAN, METHOD_EQUALS, UNFULFILLED, UNFULFILLED); checkImplies(GREATER_THAN, NOT_METHOD_EQUALS, FULFILLED, FULFILLED); } @Test public void testGreaterThanOrEqualImplies() { checkImplies(GREATER_THAN_OR_EQUAL, EQUAL, UNDETERMINED); checkImplies(GREATER_THAN_OR_EQUAL, NOT_EQUAL, UNDETERMINED); checkImplies(GREATER_THAN_OR_EQUAL, GREATER_THAN, UNDETERMINED, UNFULFILLED); checkImplies(GREATER_THAN_OR_EQUAL, GREATER_THAN_OR_EQUAL, FULFILLED, UNDETERMINED); checkImplies(GREATER_THAN_OR_EQUAL, LESS_THAN, UNFULFILLED, UNDETERMINED); checkImplies(GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, UNDETERMINED, FULFILLED); checkImplies(GREATER_THAN_OR_EQUAL, METHOD_EQUALS, UNDETERMINED); checkImplies(GREATER_THAN_OR_EQUAL, NOT_METHOD_EQUALS, UNDETERMINED); } @Test public void testLessThanImplies() { checkImplies(LESS_THAN, EQUAL, UNFULFILLED); checkImplies(LESS_THAN, NOT_EQUAL, FULFILLED); checkImplies(LESS_THAN, GREATER_THAN, UNFULFILLED, FULFILLED); checkImplies(LESS_THAN, GREATER_THAN_OR_EQUAL, UNFULFILLED, FULFILLED); checkImplies(LESS_THAN, LESS_THAN, FULFILLED, UNFULFILLED); checkImplies(LESS_THAN, LESS_THAN_OR_EQUAL, FULFILLED, UNFULFILLED); checkImplies(LESS_THAN, METHOD_EQUALS, UNDETERMINED); checkImplies(LESS_THAN, NOT_METHOD_EQUALS, UNDETERMINED); } @Test public void testLessThanOrEqualImplies() { checkImplies(LESS_THAN_OR_EQUAL, EQUAL, UNDETERMINED); checkImplies(LESS_THAN_OR_EQUAL, NOT_EQUAL, UNDETERMINED); checkImplies(LESS_THAN_OR_EQUAL, GREATER_THAN, UNFULFILLED, UNDETERMINED); checkImplies(LESS_THAN_OR_EQUAL, GREATER_THAN_OR_EQUAL, UNDETERMINED, FULFILLED); checkImplies(LESS_THAN_OR_EQUAL, LESS_THAN, UNDETERMINED, UNFULFILLED); checkImplies(LESS_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, FULFILLED, UNDETERMINED); checkImplies(LESS_THAN_OR_EQUAL, METHOD_EQUALS, UNDETERMINED); checkImplies(LESS_THAN_OR_EQUAL, NOT_METHOD_EQUALS, UNDETERMINED); } private void checkImplies(Kind tested, RelationState[] expected) { assertThat(expected).hasSize(Kind.values().length); for (Kind kind : Kind.values()) { checkImplies(tested, kind, expected[kind.ordinal()]); } } private void checkImplies(Kind hypothesisKind, Kind checkedKind, RelationState relationState) { checkImplies(hypothesisKind, checkedKind, relationState, relationState); } private void checkImplies(Kind hypothesisKind, Kind checkedKind, RelationState directResult, RelationState transposedResult) { try { BinaryRelation hypothesis = relation(hypothesisKind, SVa, SVb); BinaryRelation checked = relation(checkedKind, SVa, SVb); checkImplies(hypothesis, checked, directResult); checked = relation(checkedKind, SVb, SVa); checkImplies(hypothesis, checked, transposedResult); } catch (Exception e) { fail(e.getMessage()); } } private void checkImplies(BinaryRelation hypothesis, BinaryRelation checked, RelationState expected) { RelationState actual = hypothesis.implies(checked); assertThat(actual).as(hypothesis.toString() + " => " + checked.toString()).isEqualTo(expected); } @Test public void endlessCase() { List<BinaryRelation> knownRelations = ImmutableList.of( relation(NOT_EQUAL, SVa, SVb), // a!=b relation(EQUAL, SVa, SVc));// a==c BinaryRelation checked = new NotMethodEqualsRelation(SVb, SVa); // !b.equals(a) assertRelationHasState(checked, knownRelations, UNDETERMINED); } @Test public void transitiveEqualEqual() { checkTransitive(EQUAL, EQUAL, EQUAL, FULFILLED); checkTransitive(EQUAL, EQUAL, NOT_EQUAL, UNFULFILLED); } @Test public void transitiveEqualNotEqual() { checkTransitive(EQUAL, NOT_EQUAL, EQUAL, UNFULFILLED); checkTransitive(EQUAL, NOT_EQUAL, NOT_EQUAL, FULFILLED); checkTransitive(NOT_EQUAL, EQUAL, EQUAL, UNFULFILLED); checkTransitive(NOT_EQUAL, EQUAL, NOT_EQUAL, FULFILLED); } @Test public void transitiveEqualMethodEqual() { checkTransitive(EQUAL, METHOD_EQUALS, EQUAL, UNDETERMINED); checkTransitive(EQUAL, METHOD_EQUALS, METHOD_EQUALS, FULFILLED); checkTransitive(METHOD_EQUALS, EQUAL, EQUAL, UNDETERMINED); checkTransitive(METHOD_EQUALS, EQUAL, METHOD_EQUALS, FULFILLED); } @Test public void transitiveEqualGreater() { checkTransitive(EQUAL, GREATER_THAN, EQUAL, UNFULFILLED); checkTransitive(EQUAL, GREATER_THAN, GREATER_THAN, FULFILLED); checkTransitive(EQUAL, GREATER_THAN, NOT_EQUAL, FULFILLED); checkTransitive(EQUAL, GREATER_THAN, LESS_THAN_OR_EQUAL, UNFULFILLED); checkTransitive(GREATER_THAN, EQUAL, EQUAL, UNFULFILLED); checkTransitive(GREATER_THAN, EQUAL, GREATER_THAN, FULFILLED); checkTransitive(GREATER_THAN, EQUAL, NOT_EQUAL, FULFILLED); checkTransitive(GREATER_THAN, EQUAL, LESS_THAN_OR_EQUAL, UNFULFILLED); } @Test public void transitiveEqualGreaterOrEqual() { checkTransitive(EQUAL, GREATER_THAN_OR_EQUAL, EQUAL, UNDETERMINED); checkTransitive(EQUAL, GREATER_THAN_OR_EQUAL, GREATER_THAN_OR_EQUAL, FULFILLED); checkTransitive(EQUAL, GREATER_THAN_OR_EQUAL, NOT_EQUAL, UNDETERMINED); checkTransitive(EQUAL, GREATER_THAN_OR_EQUAL, LESS_THAN, UNFULFILLED); checkTransitive(GREATER_THAN_OR_EQUAL, EQUAL, EQUAL, UNDETERMINED); checkTransitive(GREATER_THAN_OR_EQUAL, EQUAL, GREATER_THAN_OR_EQUAL, FULFILLED); checkTransitive(GREATER_THAN_OR_EQUAL, EQUAL, NOT_EQUAL, UNDETERMINED); checkTransitive(GREATER_THAN_OR_EQUAL, EQUAL, LESS_THAN, UNFULFILLED); } @Test public void transitiveEqualLess() { checkTransitive(EQUAL, LESS_THAN, EQUAL, UNFULFILLED); checkTransitive(EQUAL, LESS_THAN, LESS_THAN, FULFILLED); checkTransitive(EQUAL, LESS_THAN, NOT_EQUAL, FULFILLED); checkTransitive(EQUAL, LESS_THAN, GREATER_THAN_OR_EQUAL, UNFULFILLED); checkTransitive(LESS_THAN, EQUAL, EQUAL, UNFULFILLED); checkTransitive(LESS_THAN, EQUAL, LESS_THAN, FULFILLED); checkTransitive(LESS_THAN, EQUAL, NOT_EQUAL, FULFILLED); checkTransitive(LESS_THAN, EQUAL, GREATER_THAN_OR_EQUAL, UNFULFILLED); } @Test public void transitiveEqualLessOrEqual() { checkTransitive(EQUAL, LESS_THAN_OR_EQUAL, EQUAL, UNDETERMINED); checkTransitive(EQUAL, LESS_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, FULFILLED); checkTransitive(EQUAL, LESS_THAN_OR_EQUAL, NOT_EQUAL, UNDETERMINED); checkTransitive(EQUAL, LESS_THAN_OR_EQUAL, GREATER_THAN, UNFULFILLED); checkTransitive(LESS_THAN_OR_EQUAL, EQUAL, EQUAL, UNDETERMINED); checkTransitive(LESS_THAN_OR_EQUAL, EQUAL, LESS_THAN_OR_EQUAL, FULFILLED); checkTransitive(LESS_THAN_OR_EQUAL, EQUAL, NOT_EQUAL, UNDETERMINED); checkTransitive(LESS_THAN_OR_EQUAL, EQUAL, GREATER_THAN, UNFULFILLED); } @Test public void transitiveMethodEquals() { checkTransitive(METHOD_EQUALS, new RelationState[]{FULFILLED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNFULFILLED, UNDETERMINED, FULFILLED, UNFULFILLED}); checkTransitive(NOT_METHOD_EQUALS, new RelationState[]{FULFILLED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNDETERMINED, UNDETERMINED, FULFILLED, UNDETERMINED}); } @Test public void transitiveLessThanOrEqual() { checkTransitive(LESS_THAN_OR_EQUAL, new RelationState[]{FULFILLED, UNDETERMINED, UNDETERMINED, UNDETERMINED, FULFILLED, FULFILLED, FULFILLED, UNDETERMINED}); checkTransitive(LESS_THAN, new RelationState[]{FULFILLED, UNDETERMINED, UNDETERMINED, UNDETERMINED, FULFILLED, FULFILLED, FULFILLED, UNDETERMINED}); } private void checkTransitive(Kind hKind1, RelationState[] expectedRelationState) { for (Kind kind : Kind.values()) { checkTransitive(hKind1, kind, hKind1, expectedRelationState[kind.ordinal()]); } } private void checkTransitive(Kind hKind1, Kind hkind2, Kind checkedKind, RelationState directResult) { try { BinaryRelation hypothesis1 = relation(hKind1, SVa, SVb); BinaryRelation hypothesis2 = relation(hkind2, SVb, SVc); BinaryRelation checked = relation(checkedKind, SVa, SVc); checkTransitive(hypothesis1, hypothesis2, checked, directResult); checkTransitive(hypothesis1.symmetric(), hypothesis2, checked, directResult); checkTransitive(hypothesis1, hypothesis2.symmetric(), checked, directResult); checkTransitive(hypothesis1, hypothesis2, checked.symmetric(), directResult); } catch (Exception e) { fail(e.getMessage()); } } @Test public void checkEquality() { BinaryRelation rel = relation(EQUAL, SVa, SVb); assertThat(rel).isNotEqualTo(""); assertThat(rel).isEqualTo(relation(EQUAL, SVa, SVb)); assertThat(rel).isNotEqualTo(relation(NOT_EQUAL, SVa, SVb)); assertThat(rel).isNotEqualTo(relation(EQUAL, SVa, SVc)); } @Test public void checkTransitiveLimit() { List<BinaryRelation> relations = new ArrayList<>(); SymbolicValue first = null; SymbolicValue previous = null; SymbolicValue last = null; for (int i = 0; i < 300; i++) { last = new SymbolicValue(i); if (first == null) { first = last; } else if (previous != null) { relations.add(relation(EQUAL, previous, last)); } previous = last; } try { relation(EQUAL, first, last).resolveState(relations); fail("Transitive limit was exceeded, but not detected!"); } catch (BinaryRelation.TransitiveRelationExceededException e) { assertThat(e.getMessage()).contains("exceeded"); } } @Test public void transitiveConjunction() { checkConjunction(LESS_THAN_OR_EQUAL, GREATER_THAN_OR_EQUAL, EQUAL, FULFILLED); checkConjunction(LESS_THAN_OR_EQUAL, NOT_EQUAL, LESS_THAN, FULFILLED); checkConjunction(GREATER_THAN_OR_EQUAL, NOT_EQUAL, GREATER_THAN, FULFILLED); checkConjunction(LESS_THAN_OR_EQUAL, NOT_METHOD_EQUALS, LESS_THAN, FULFILLED); checkConjunction(GREATER_THAN_OR_EQUAL, NOT_METHOD_EQUALS, GREATER_THAN, FULFILLED); checkConjunction(GREATER_THAN_OR_EQUAL, METHOD_EQUALS, EQUAL, UNDETERMINED); checkConjunction(NOT_METHOD_EQUALS, NOT_EQUAL, LESS_THAN, UNDETERMINED); } private void checkConjunction(Kind hKind1, Kind hKind2, Kind checkedKind, RelationState directResult) { try { BinaryRelation hypothesis1 = relation(hKind1, SVa, SVb); BinaryRelation hypothesis2 = relation(hKind2, SVa, SVb); BinaryRelation checked = relation(checkedKind, SVa, SVb); checkTransitive(hypothesis1, hypothesis2, checked, directResult); checkTransitive(hypothesis2, hypothesis1, checked, directResult); } catch (Exception e) { fail(e.getMessage()); } } @Test public void combinedTest() { checkCombined(EQUAL, new Kind[]{EQUAL, NOT_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, METHOD_EQUALS, null}); checkCombined(NOT_EQUAL, new Kind[]{NOT_EQUAL, null, null, null, null, null, null, null}); checkCombined(GREATER_THAN_OR_EQUAL, new Kind[]{GREATER_THAN_OR_EQUAL, null, GREATER_THAN, GREATER_THAN_OR_EQUAL, null, null, GREATER_THAN_OR_EQUAL, null}); checkCombined(GREATER_THAN, new Kind[]{GREATER_THAN, null, GREATER_THAN, GREATER_THAN, null, null, GREATER_THAN, null}); checkCombined(LESS_THAN_OR_EQUAL, new Kind[]{LESS_THAN_OR_EQUAL, null, null, null, LESS_THAN, LESS_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, null}); checkCombined(LESS_THAN, new Kind[]{LESS_THAN, null, null, null, LESS_THAN, LESS_THAN, LESS_THAN, null}); checkCombined(METHOD_EQUALS, new Kind[]{METHOD_EQUALS, null, null, GREATER_THAN_OR_EQUAL, null, LESS_THAN_OR_EQUAL, METHOD_EQUALS, null}); checkCombined(NOT_METHOD_EQUALS, new Kind[]{NOT_METHOD_EQUALS, null, null, null, null, null, NOT_METHOD_EQUALS, null}); } private void checkCombined(Kind tested, Kind[] expected) { assertThat(expected).hasSize(Kind.values().length); for (Kind kind : Kind.values()) { checkCombined(tested, kind, expected[kind.ordinal()]); } } private void checkCombined(Kind hKind1, Kind hKind2, Kind checkedKind) { try { BinaryRelation hypothesis1 = relation(hKind1, SVa, SVb); BinaryRelation hypothesis2 = relation(hKind2, SVb, SVc); if (checkedKind == null) { assertThat(hypothesis1.combineUnordered(hypothesis2)).isNull(); } else { BinaryRelation checked = relation(checkedKind, SVa, SVc); assertThat(hypothesis1.combineUnordered(hypothesis2)).isEqualTo(checked); } } catch (Exception e) { fail(e.getMessage()); } } @Test public void testToString() { assertThat(relation(EQUAL, SVa, SVb).toString()).isEqualTo("SV_0==SV_1"); } }