diff --git a/client-java/distance-heuristics/src/main/java/org/evomaster/client/java/distance/heuristics/TruthnessUtils.java b/client-java/distance-heuristics/src/main/java/org/evomaster/client/java/distance/heuristics/TruthnessUtils.java index 3b5301c601..e41a8846d2 100644 --- a/client-java/distance-heuristics/src/main/java/org/evomaster/client/java/distance/heuristics/TruthnessUtils.java +++ b/client-java/distance-heuristics/src/main/java/org/evomaster/client/java/distance/heuristics/TruthnessUtils.java @@ -46,6 +46,15 @@ public static Truthness getEqualityTruthness(long a, long b) { ); } + + public static Truthness getLessThanTruthness(double a, double b) { + double distance = DistanceHelper.getDistanceToEquality(a, b); + return new Truthness( + a < b ? 1d : 1d / (1.1d + distance), + a >= b ? 1d : 1d / (1.1d + distance) + ); + } + public static Truthness getLessThanTruthness(long a, long b) { double distance = DistanceHelper.getDistanceToEquality(a, b); return new Truthness( diff --git a/client-java/sql/src/main/java/org/evomaster/client/java/sql/internal/SqlExpressionEvaluator.java b/client-java/sql/src/main/java/org/evomaster/client/java/sql/internal/SqlExpressionEvaluator.java index 874dd52395..50744c842a 100644 --- a/client-java/sql/src/main/java/org/evomaster/client/java/sql/internal/SqlExpressionEvaluator.java +++ b/client-java/sql/src/main/java/org/evomaster/client/java/sql/internal/SqlExpressionEvaluator.java @@ -11,7 +11,6 @@ import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.Select; -import org.evomaster.client.java.distance.heuristics.DistanceHelper; import org.evomaster.client.java.distance.heuristics.Truthness; import org.evomaster.client.java.distance.heuristics.TruthnessUtils; import org.evomaster.client.java.sql.DataRow; @@ -40,22 +39,49 @@ public Truthness getEvaluatedTruthness() { return computedTruthnesses.peek(); } + private void visitComparisonOperator(ComparisonOperator comparisonOperator) { + final Object concreteRightValue = concreteValues.pop(); + final Object concreteLeftValue = concreteValues.pop(); + final Truthness truthness = computeTruthnessForComparisonOperator(concreteLeftValue, concreteRightValue, comparisonOperator); + computedTruthnesses.push(truthness); + } + @Override public void visit(EqualsTo equalsTo) { super.visit(equalsTo); - final Object concreteRightValue = concreteValues.pop(); - final Object concreteLeftValue = concreteValues.pop(); + visitComparisonOperator(equalsTo); + } + + private Truthness computeTruthnessForComparisonOperator(Object concreteLeftValue, Object concreteRightValue, ComparisonOperator comparisonOperator) { final Truthness truthness; if (concreteLeftValue == null && concreteRightValue == null) { truthness = SqlHeuristicsCalculator.FALSE_TRUTHNESS; } else if (concreteLeftValue == null || concreteRightValue == null) { truthness = SqlHeuristicsCalculator.FALSE_TRUTHNESS_BETTER; } else { - final double ofTrue; + final Truthness truthnessOfExpression; if (concreteLeftValue instanceof Number && concreteRightValue instanceof Number) { double leftValueAsDouble = ((Number) concreteLeftValue).doubleValue(); double rightValueAsDouble = ((Number) concreteRightValue).doubleValue(); - ofTrue = TruthnessUtils.getEqualityTruthness(leftValueAsDouble, rightValueAsDouble).getOfTrue(); + if (comparisonOperator instanceof EqualsTo) { + truthnessOfExpression = TruthnessUtils.getEqualityTruthness(leftValueAsDouble, rightValueAsDouble); + } else if (comparisonOperator instanceof NotEqualsTo) { + //a != b => !(a == b) + truthnessOfExpression = TruthnessUtils.getEqualityTruthness(leftValueAsDouble, rightValueAsDouble).invert(); + } else if (comparisonOperator instanceof GreaterThan) { + //a > b => b < a + truthnessOfExpression = TruthnessUtils.getLessThanTruthness(rightValueAsDouble, leftValueAsDouble); + } else if (comparisonOperator instanceof MinorThan) { + truthnessOfExpression = TruthnessUtils.getLessThanTruthness(leftValueAsDouble, rightValueAsDouble); + } else if (comparisonOperator instanceof MinorThanEquals) { + //a <= b => b >= a => !(b < a) + truthnessOfExpression = TruthnessUtils.getLessThanTruthness(rightValueAsDouble, leftValueAsDouble).invert(); + } else if (comparisonOperator instanceof GreaterThanEquals) { + //a >= b => ! (a < b) + truthnessOfExpression = TruthnessUtils.getLessThanTruthness(leftValueAsDouble, rightValueAsDouble).invert(); + } else { + throw new UnsupportedOperationException("Unsupported comparison operator: " + comparisonOperator); + } } else if (concreteRightValue instanceof String && concreteLeftValue instanceof String) { throw new UnsupportedOperationException("String comparison not yet supported"); } else if (concreteLeftValue instanceof Timestamp || concreteRightValue instanceof Timestamp @@ -66,9 +92,13 @@ public void visit(EqualsTo equalsTo) { } else { throw new UnsupportedOperationException("type not supported"); } - truthness = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C_BETTER, ofTrue); + if (truthnessOfExpression.isTrue()) { + truthness = truthnessOfExpression; + } else { + truthness = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C_BETTER, truthnessOfExpression.getOfTrue()); + } } - computedTruthnesses.push(truthness); + return truthness; } @Override @@ -185,12 +215,14 @@ public void visit(OverlapsCondition overlapsCondition) { @Override public void visit(GreaterThan greaterThan) { - throw new UnsupportedOperationException("visit(GreaterThan) not supported"); + super.visit(greaterThan); + this.visitComparisonOperator(greaterThan); } @Override public void visit(GreaterThanEquals greaterThanEquals) { - throw new UnsupportedOperationException("visit(GreaterThanEquals) not supported"); + super.visit(greaterThanEquals); + this.visitComparisonOperator(greaterThanEquals); } @Override @@ -220,17 +252,20 @@ public void visit(LikeExpression likeExpression) { @Override public void visit(MinorThan minorThan) { - throw new UnsupportedOperationException("visit(MinorThan) not supported"); + super.visit(minorThan); + visitComparisonOperator(minorThan); } @Override public void visit(MinorThanEquals minorThanEquals) { - throw new UnsupportedOperationException("visit(MinorThanEquals) not supported"); + super.visit(minorThanEquals); + visitComparisonOperator(minorThanEquals); } @Override public void visit(NotEqualsTo notEqualsTo) { - throw new UnsupportedOperationException("visit(NotEqualsTo) not supported"); + super.visit(notEqualsTo); + visitComparisonOperator(notEqualsTo); } @Override diff --git a/client-java/sql/src/test/java/org/evomaster/client/java/sql/internal/SqlHeuristicsCalculatorTest.java b/client-java/sql/src/test/java/org/evomaster/client/java/sql/internal/SqlHeuristicsCalculatorTest.java index bc8e7583bd..ad13e014a4 100644 --- a/client-java/sql/src/test/java/org/evomaster/client/java/sql/internal/SqlHeuristicsCalculatorTest.java +++ b/client-java/sql/src/test/java/org/evomaster/client/java/sql/internal/SqlHeuristicsCalculatorTest.java @@ -157,17 +157,72 @@ public void testCrossJoinNoFromTableWithRows() { } @Test - public void testSelectWithWhereNoRows() { + public void testSelectNotEquals() { String sqlCommand = "SELECT name, age FROM Persons WHERE age=18"; QueryResult personsContents = new QueryResult(Arrays.asList("name","age"), "Persons"); - personsContents.addRow(Arrays.asList("name","age"),"Persons",Arrays.asList("John", 15)); + personsContents.addRow(Arrays.asList("name","age"),"Persons",Arrays.asList("John", 18)); + SqlDistanceWithMetrics distanceWithMetrics = SqlHeuristicsCalculator.computeDistance(sqlCommand, null, null, personsContents); + assertEquals(0.0, distanceWithMetrics.sqlDistance); + } + + @Test + public void testSelectMinorThan() { + String sqlCommand = "SELECT name, age FROM Persons WHERE age<18"; + QueryResult personsContents = new QueryResult(Arrays.asList("name","age"), "Persons"); + personsContents.addRow(Arrays.asList("name","age"),"Persons",Arrays.asList("John", 33)); + SqlDistanceWithMetrics distanceWithMetrics = SqlHeuristicsCalculator.computeDistance(sqlCommand, null, null, personsContents); + + double equalityTruthness = TruthnessUtils.getLessThanTruthness(33.0d, 18.0d).getOfTrue(); + double scaledTruthnessBetter = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C_BETTER, equalityTruthness).getOfTrue(); + double scaledTruthness = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C, scaledTruthnessBetter).getOfTrue(); + double expectedDistance = 1 - scaledTruthness; + + assertEquals(expectedDistance, distanceWithMetrics.sqlDistance); + } + + @Test + public void testSelectMinorThanEquals() { + String sqlCommand = "SELECT name, age FROM Persons WHERE age<=18"; + QueryResult personsContents = new QueryResult(Arrays.asList("name","age"), "Persons"); + personsContents.addRow(Arrays.asList("name","age"),"Persons",Arrays.asList("John", 33)); SqlDistanceWithMetrics distanceWithMetrics = SqlHeuristicsCalculator.computeDistance(sqlCommand, null, null, personsContents); - double equalityTruthness = TruthnessUtils.getEqualityTruthness(15.0d, 18.0d).getOfTrue(); + double equalityTruthness = TruthnessUtils.getLessThanTruthness(18.0d, 33.0d).invert().getOfTrue(); double scaledTruthnessBetter = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C_BETTER, equalityTruthness).getOfTrue(); double scaledTruthness = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C, scaledTruthnessBetter).getOfTrue(); double expectedDistance = 1 - scaledTruthness; assertEquals(expectedDistance, distanceWithMetrics.sqlDistance); } + + @Test + public void testSelectGreaterThan() { + String sqlCommand = "SELECT name, age FROM Persons WHERE 18>age"; + QueryResult personsContents = new QueryResult(Arrays.asList("name","age"), "Persons"); + personsContents.addRow(Arrays.asList("name","age"),"Persons",Arrays.asList("John", 33)); + SqlDistanceWithMetrics distanceWithMetrics = SqlHeuristicsCalculator.computeDistance(sqlCommand, null, null, personsContents); + + double equalityTruthness = TruthnessUtils.getLessThanTruthness( 33,18.0d).getOfTrue(); + double scaledTruthnessBetter = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C_BETTER, equalityTruthness).getOfTrue(); + double scaledTruthness = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C, scaledTruthnessBetter).getOfTrue(); + double expectedDistance = 1 - scaledTruthness; + + assertEquals(expectedDistance, distanceWithMetrics.sqlDistance); + } + + @Test + public void testSelectGreaterThanEquals() { + String sqlCommand = "SELECT name, age FROM Persons WHERE 18>=age"; + QueryResult personsContents = new QueryResult(Arrays.asList("name","age"), "Persons"); + personsContents.addRow(Arrays.asList("name","age"),"Persons",Arrays.asList("John", 33)); + SqlDistanceWithMetrics distanceWithMetrics = SqlHeuristicsCalculator.computeDistance(sqlCommand, null, null, personsContents); + + double equalityTruthness = TruthnessUtils.getLessThanTruthness( 18,33.0d).invert().getOfTrue(); + double scaledTruthnessBetter = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C_BETTER, equalityTruthness).getOfTrue(); + double scaledTruthness = TruthnessUtils.buildScaledTruthness(SqlHeuristicsCalculator.C, scaledTruthnessBetter).getOfTrue(); + double expectedDistance = 1 - scaledTruthness; + + assertEquals(expectedDistance, distanceWithMetrics.sqlDistance); + } + }