This is an automated email from the ASF dual-hosted git repository. andy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
commit ca1ec6cfedf3563df598b79565f0dbcd4f6de754 Author: Andy Seaborne <[email protected]> AuthorDate: Tue Dec 30 19:04:31 2025 +0000 GH-3674: Fix ROUND() --- .../org/apache/jena/sparql/util/XSDNumUtils.java | 20 +- .../apache/jena/sparql/expr/TestFunctions2.java | 323 ++++++++++----------- .../org/apache/jena/sparql/expr/TestXSDFuncOp.java | 98 +++++++ 3 files changed, 267 insertions(+), 174 deletions(-) diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java b/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java index aa884ce0ca..91d6a3fdb5 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java @@ -20,6 +20,9 @@ package org.apache.jena.sparql.util; import java.math.BigDecimal; +import org.apache.jena.sparql.expr.ExprEvalException; +import org.apache.jena.sparql.expr.NodeValue; + public class XSDNumUtils { /** @@ -35,7 +38,7 @@ public class XSDNumUtils { case "+INF", "+inf" -> Double.POSITIVE_INFINITY; case "-INF", "-inf" -> Double.NEGATIVE_INFINITY; case "NaN" -> Double.NaN ; - // Acceptable as Java doubles (value is "NaN" but not as xsd:double + // Acceptable as Java doubles (value is "NaN" but not as xsd:double) case "-NaN"-> throw new NumberFormatException("-NaN is not valid as an xsd:double"); case "+NaN"-> throw new NumberFormatException("+NaN is not valid as an xsd:double"); // Includes +0 and -0. @@ -64,6 +67,20 @@ public class XSDNumUtils { }; } + /** + * isNaN() - for xsd:double and xsd:float. + * The argument must be numeric; if not, this function throws {@link ExprEvalException}. + */ + public static boolean isNaN(NodeValue nv) { + if ( ! nv.isNumber() ) + throw new ExprEvalException("Not a numeric datatype"); + if ( nv.isDouble() ) + return Double.isNaN(nv.getDouble()); + if ( nv.isFloat() ) + return Float.isNaN(nv.getFloat()); + return false; + } + /** Parse an XSD decimal. */ public static BigDecimal xsdParseDecimal(String lexicalForm) { return new BigDecimal(lexicalForm); @@ -120,7 +137,6 @@ public class XSDNumUtils { return canonicalDecimalStrWithDot(bd); } - /** * Strict XSD 1.0 format for {@code xsd:decimal}. * <p> diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java index 6b72e2ff78..44b5ef44e1 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java @@ -19,13 +19,14 @@ package org.apache.jena.sparql.expr; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.apache.jena.datatypes.RDFDatatype; import org.apache.jena.graph.Node; import org.apache.jena.shared.PrefixMapping; import org.apache.jena.sparql.ARQConstants; @@ -91,61 +92,68 @@ public class TestFunctions2 // Any same value would do - we test for the exact lexical form // of the implementation. - @Test public void round_01() { test("round(123)", "123"); } - @Test public void round_02() { test("round(123.5)", "'124.0'^^xsd:decimal"); } - @Test public void round_03() { test("round(-0.5e0)", "0.0e0"); } - @Test public void round_04() { test("round(-1.5)", "'-1.0'^^xsd:decimal"); } - @Test public void round_05() { test("round(-0)", "-0"); } - - @Test public void abs_01() { test("abs(1)", "1"); } - @Test public void abs_02() { test("abs(1.0)", "1.0"); } - @Test public void abs_03() { test("abs(1.0e0)", "1.0e0"); } - @Test public void abs_04() { test("abs(-1)", "1"); } - @Test public void abs_05() { test("abs(+0)", "0"); } - @Test public void abs_06() { test("abs(-0)", "0"); } + // ROUND + @Test public void round_01() { test("round(123)", "123"); } + @Test public void round_02() { test("round(123.5)", "'124.0'^^xsd:decimal"); } + @Test public void round_03() { test("round(-0.5e0)", "-0.0e0"); } + @Test public void round_04() { test("round(-1.5)", "'-1.0'^^xsd:decimal"); } + @Test public void round_05() { test("round(-0)", "-0"); } + + @Test public void round_10() { test("round('NaN'^^xsd:double)", "'NaN'^^xsd:double"); } + @Test public void round_11() { test("round('NaN'^^xsd:float)", "'NaN'^^xsd:float"); } + @Test public void round_12() { test("round('-0'^^xsd:double)", "'-0.0e0'^^xsd:double"); } + @Test public void round_13() { test("round('-0'^^xsd:float)", "'-0.0'^^xsd:float"); } + @Test public void round_14() { test("round('-0'^^xsd:double)", "'-0.0e0'^^xsd:double"); } + + @Test public void abs_01() { test("abs(1)", "1"); } + @Test public void abs_02() { test("abs(1.0)", "1.0"); } + @Test public void abs_03() { test("abs(1.0e0)", "1.0e0"); } + @Test public void abs_04() { test("abs(-1)", "1"); } + @Test public void abs_05() { test("abs(+0)", "0"); } + @Test public void abs_06() { test("abs(-0)", "0"); } // CEIL - @Test public void ceil_01() { test("ceil(1)", "1"); } - @Test public void ceil_02() { test("ceil(1.0)", "'1.0'^^xsd:decimal"); } - @Test public void ceil_03() { test("ceil(1e0)", "1.0e0"); } - @Test public void ceil_04() { test("ceil(1.5e0)", "2.0e0"); } - @Test public void ceil_05() { test("ceil(-0.9)", "'0.0'^^xsd:decimal"); } - @Test public void ceil_06() { test("ceil(-9)", "-9"); } - @Test public void ceil_07() { test("ceil(-9.5)", "'-9.0'^^xsd:decimal"); } - @Test public void ceil_08() { test("ceil(0)", "0"); } + @Test public void ceil_01() { test("ceil(1)", "1"); } + @Test public void ceil_02() { test("ceil(1.0)", "'1.0'^^xsd:decimal"); } + @Test public void ceil_03() { test("ceil(1e0)", "1.0e0"); } + @Test public void ceil_04() { test("ceil(1.5e0)", "2.0e0"); } + @Test public void ceil_05() { test("ceil(-0.9)", "'0.0'^^xsd:decimal"); } + @Test public void ceil_06() { test("ceil(-9)", "-9"); } + @Test public void ceil_07() { test("ceil(-9.5)", "'-9.0'^^xsd:decimal"); } + @Test public void ceil_08() { test("ceil(0)", "0"); } // FLOOR - @Test public void floor_01() { test("floor(1)", "1"); } - @Test public void floor_02() { test("floor(1.0)", "'1.0'^^xsd:decimal"); } - @Test public void floor_03() { test("floor(1e0)", "1.0e0"); } - @Test public void floor_04() { test("floor(1.5e0)", "1.0e0"); } - @Test public void floor_05() { test("floor(-0.9)", "'-1.0'^^xsd:decimal"); } - @Test public void floor_06() { test("floor(-9)", "-9"); } - @Test public void floor_07() { test("floor(-9.5)", "'-10.0'^^xsd:decimal"); } - @Test public void floor_08() { test("floor(0)", "0"); } + @Test public void floor_01() { test("floor(1)", "1"); } + @Test public void floor_02() { test("floor(1.0)", "'1.0'^^xsd:decimal"); } + @Test public void floor_03() { test("floor(1e0)", "1.0e0"); } + @Test public void floor_04() { test("floor(1.5e0)", "1.0e0"); } + @Test public void floor_05() { test("floor(-0.9)", "'-1.0'^^xsd:decimal"); } + @Test public void floor_06() { test("floor(-9)", "-9"); } + @Test public void floor_07() { test("floor(-9.5)", "'-10.0'^^xsd:decimal"); } + @Test public void floor_08() { test("floor(0)", "0"); } - // simple, PLWL, xsd:string. // CONCAT - @Test public void concat_01() { test("concat('a')", "'a'"); } - @Test public void concat_02() { test("concat('a', 'b')", "'ab'"); } - @Test public void concat_03() { test("concat('a'@en, 'b')", "'ab'"); } - @Test public void concat_04() { test("concat('a'@en, 'b'@en)", "'ab'@en"); } - //@Test public void concat_05() { test("concat('a'^^xsd:string, 'b')", "'ab'^^xsd:string"); } - @Test public void concat_05() { test("concat('a'^^xsd:string, 'b')", "'ab'"); } - @Test public void concat_06() { test("concat('a'^^xsd:string, 'b'^^xsd:string)", "'ab'^^xsd:string"); } - @Test public void concat_07() { test("concat('a'^^xsd:string, 'b'^^xsd:string)", "'ab'^^xsd:string"); } + @Test public void concat_00() { test("concat()", "''"); } + @Test public void concat_01() { test("concat('a')", "'a'"); } + @Test public void concat_02() { test("concat('a', 'b')", "'ab'"); } + @Test public void concat_03() { test("concat('a'@en, 'b')", "'ab'"); } + @Test public void concat_04() { test("concat('a'@en, 'b'@en)", "'ab'@en"); } + //@Test public void concat_05() { test("concat('a'^^xsd:string, 'b')", "'ab'^^xsd:string"); } + @Test public void concat_05() { test("concat('a'^^xsd:string, 'b')", "'ab'"); } + @Test public void concat_06() { test("concat('a'^^xsd:string, 'b'^^xsd:string)", "'ab'^^xsd:string"); } + @Test public void concat_07() { test("concat('a'^^xsd:string, 'b'^^xsd:string)", "'ab'^^xsd:string"); } //@Test public void concat_08() { test("concat('a', 'b'^^xsd:string)", "'ab'^^xsd:string"); } - @Test public void concat_08() { test("concat('a', 'b'^^xsd:string)", "'ab'"); } - @Test public void concat_09() { test("concat('a'@en, 'b'^^xsd:string)", "'ab'"); } - @Test public void concat_10() { test("concat('a'^^xsd:string, 'b'@en)", "'ab'"); } - @Test public void concat_11() { test("concat()", "''"); } + @Test public void concat_08() { test("concat('a', 'b'^^xsd:string)", "'ab'"); } + @Test public void concat_09() { test("concat('a'@en, 'b'^^xsd:string)", "'ab'"); } + @Test public void concat_10() { test("concat('a'^^xsd:string, 'b'@en)", "'ab'"); } + @Test public void concat_11() { test("concat()", "''"); } @Test public void concat_90() { assertThrows(ExprEvalException.class, ()-> test("concat(1)", "1") ); } @Test - public void concat_91() { test("concat('a'@en, 'b'@fr)", "'ab'"); } + public void concat_91() { test("concat('a'@en, 'b'@fr)", "'ab'"); } // SUBSTR @Test public void substr_01() { test("substr('abc',1)", "'abc'"); } @@ -156,15 +164,15 @@ public class TestFunctions2 @Test public void substr_06() { test("substr('12345',-1,3)", "'1'"); } // These are the examples in F&O - @Test public void substr_10() { test("substr('motor car', 6)", "' car'"); } - @Test public void substr_11() { test("substr('metadata', 4, 3)", "'ada'"); } - @Test public void substr_12() { test("substr('12345', 1.5, 2.6)", "'234'"); } - @Test public void substr_13() { test("substr('12345', 0, 3)", "'12'"); } - @Test public void substr_14() { test("substr('12345', 5, -3)", "''"); } - @Test public void substr_15() { test("substr('12345', -3, 5)", "'1'"); } - @Test public void substr_16() { test("substr('12345', 0/0E0, 3)", "''"); } - @Test public void substr_17() { test("substr('12345', 1, 0/0E0)", "''"); } - @Test public void substr_18() { test("substr('', 1, 3)", "''"); } + @Test public void substr_10() { test("substr('motor car', 6)", "' car'"); } + @Test public void substr_11() { test("substr('metadata', 4, 3)", "'ada'"); } + @Test public void substr_12() { test("substr('12345', 1.5, 2.6)", "'234'"); } + @Test public void substr_13() { test("substr('12345', 0, 3)", "'12'"); } + @Test public void substr_14() { test("substr('12345', 5, -3)", "''"); } + @Test public void substr_15() { test("substr('12345', -3, 5)", "'1'"); } + @Test public void substr_16() { test("substr('12345', 0/0E0, 3)", "''"); } + @Test public void substr_17() { test("substr('12345', 1, 0/0E0)", "''"); } + @Test public void substr_18() { test("substr('', 1, 3)", "''"); } @Test public void substr_20() { assertThrows(ExprEvalException.class, ()-> test("substr(1, 1, 3)", "''") ); } @@ -226,35 +234,30 @@ public class TestFunctions2 */ // CONTAINS - @Test public void contains_01() { test("contains('abc', 'a')", "true"); } - @Test public void contains_02() { test("contains('abc', 'b')", "true"); } - @Test public void contains_03() { test("contains('ABC', 'a')", "false"); } - @Test public void contains_04() { test("contains('abc', '')", "true"); } - @Test public void contains_05() { test("contains('', '')", "true"); } - @Test public void contains_06() { test("contains('', 'a')", "false"); } - @Test public void contains_07() { test("contains('12345', '34')", "true"); } - @Test public void contains_08() { test("contains('12345', '123456')", "false"); } + @Test public void contains_01() { test("contains('abc', 'a')", "true"); } + @Test public void contains_02() { test("contains('abc', 'b')", "true"); } + @Test public void contains_03() { test("contains('ABC', 'a')", "false"); } + @Test public void contains_04() { test("contains('abc', '')", "true"); } + @Test public void contains_05() { test("contains('', '')", "true"); } + @Test public void contains_06() { test("contains('', 'a')", "false"); } + @Test public void contains_07() { test("contains('12345', '34')", "true"); } + @Test public void contains_08() { test("contains('12345', '123456')", "false"); } - @Test public void contains_10() { test("contains('abc', 'a'^^xsd:string)", "true"); } - @Test - public void contains_11() { assertThrows(ExprEvalException.class, ()-> test("contains('abc', 'a'@en)", "true") ); } + @Test public void contains_10() { test("contains('abc', 'a'^^xsd:string)", "true"); } + @Test public void contains_11() { assertThrows(ExprEvalException.class, ()-> test("contains('abc', 'a'@en)", "true") ); } - @Test public void contains_12() { test("contains('abc'@en, 'a')", "true"); } - @Test public void contains_13() { test("contains('abc'@en, 'a'^^xsd:string)", "true"); } - @Test public void contains_14() { test("contains('abc'@en, 'a'@en)", "true"); } - @Test - public void contains_15() { assertThrows(ExprEvalException.class, ()-> test("contains('abc'@en, 'a'@fr)", "true") ); } + @Test public void contains_12() { test("contains('abc'@en, 'a')", "true"); } + @Test public void contains_13() { test("contains('abc'@en, 'a'^^xsd:string)", "true"); } + @Test public void contains_14() { test("contains('abc'@en, 'a'@en)", "true"); } + @Test public void contains_15() { assertThrows(ExprEvalException.class, ()-> test("contains('abc'@en, 'a'@fr)", "true") ); } - @Test public void contains_16() { test("contains('abc'^^xsd:string, 'a')", "true"); } + @Test public void contains_16() { test("contains('abc'^^xsd:string, 'a')", "true"); } - @Test - public void contains_17() { assertThrows(ExprEvalException.class, ()-> test("contains('abc'^^xsd:string, 'a'@en)", "true") ); } - @Test public void contains_18() { test("contains('abc'^^xsd:string, 'a'^^xsd:string)", "true"); } + @Test public void contains_17() { assertThrows(ExprEvalException.class, ()-> test("contains('abc'^^xsd:string, 'a'@en)", "true") ); } + @Test public void contains_18() { test("contains('abc'^^xsd:string, 'a'^^xsd:string)", "true"); } - @Test - public void contains_20() { assertThrows(ExprEvalException.class, ()-> test("contains(1816, 'a'^^xsd:string)", "true") ); } - @Test - public void contains_21() { assertThrows(ExprEvalException.class, ()-> test("contains('abc', 1066)", "true") ); } + @Test public void contains_20() { assertThrows(ExprEvalException.class, ()-> test("contains(1816, 'a'^^xsd:string)", "true") ); } + @Test public void contains_21() { assertThrows(ExprEvalException.class, ()-> test("contains('abc', 1066)", "true") ); } @Test public void strstarts_01() { test("strstarts('abc', 'a')", "true"); } @Test public void strstarts_02() { test("strstarts('abc', 'b')", "false"); } @@ -264,8 +267,7 @@ public class TestFunctions2 @Test public void strstarts_06() { test("strstarts('', 'a')", "false"); } @Test public void strstarts_10() { test("strstarts('abc', 'a'^^xsd:string)", "true"); } - @Test - public void strstarts_11() { assertThrows(ExprEvalException.class, ()-> test("strstarts('abc', 'a'@en)", "true") ); } + @Test public void strstarts_11() { assertThrows(ExprEvalException.class, ()-> test("strstarts('abc', 'a'@en)", "true") ); } @Test public void strstarts_12() { test("strstarts('abc'@en, 'a')", "true"); } @Test public void strstarts_13() { test("strstarts('abc'@en, 'a'^^xsd:string)", "true"); } @@ -279,10 +281,8 @@ public class TestFunctions2 public void strstarts_17() { assertThrows(ExprEvalException.class, ()-> test("strstarts('abc'^^xsd:string, 'a'@en)", "true") ); } @Test public void strstarts_18() { test("strstarts('abc'^^xsd:string, 'a'^^xsd:string)", "true"); } - @Test - public void strstarts_20() { assertThrows(ExprEvalException.class, ()-> test("strstarts(1816, 'a'^^xsd:string)", "true") ); } - @Test - public void strstarts_21() { assertThrows(ExprEvalException.class, ()-> test("strstarts('abc', 1066)", "true") ); } + @Test public void strstarts_20() { assertThrows(ExprEvalException.class, ()-> test("strstarts(1816, 'a'^^xsd:string)", "true") ); } + @Test public void strstarts_21() { assertThrows(ExprEvalException.class, ()-> test("strstarts('abc', 1066)", "true") ); } // STRENDS @Test public void strends_01() { test("strends('abc', 'c')", "true"); } @@ -293,8 +293,7 @@ public class TestFunctions2 @Test public void strends_06() { test("strends('', 'a')", "false"); } @Test public void strends_10() { test("strends('abc', 'c'^^xsd:string)", "true"); } - @Test - public void strends11() { assertThrows(ExprEvalException.class, ()-> test("strends('abc', 'c'@en)", "true") ); } + @Test public void strends11() { assertThrows(ExprEvalException.class, ()-> test("strends('abc', 'c'@en)", "true") ); } @Test public void strends_12() { test("strends('abc'@en, 'c')", "true"); } @Test public void strends_13() { test("strends('abc'@en, 'c'^^xsd:string)", "true"); } @@ -307,10 +306,8 @@ public class TestFunctions2 public void strends_17() { assertThrows(ExprEvalException.class, ()-> test("strends('abc'^^xsd:string, 'a'@en)", "true") ); } @Test public void strends_18() { test("strends('abc'^^xsd:string, 'abc'^^xsd:string)", "true"); } - @Test - public void strends_20() { assertThrows(ExprEvalException.class, ()-> test("strends(1816, '6'^^xsd:string)", "true") ); } - @Test - public void strends_21() { assertThrows(ExprEvalException.class, ()-> test("strends('abc', 1066)", "true") ); } + @Test public void strends_20() { assertThrows(ExprEvalException.class, ()-> test("strends(1816, '6'^^xsd:string)", "true") ); } + @Test public void strends_21() { assertThrows(ExprEvalException.class, ()-> test("strends('abc', 1066)", "true") ); } // YEAR @Test public void year_01() { test("year('2010-12-24T16:24:01.123'^^xsd:dateTime)", "2010"); } @@ -436,49 +433,45 @@ public class TestFunctions2 @Test public void hours_20() { test("hours('2010-12-24T16:24:01.123-08:00'^^xsd:dateTime)", "16"); } @Test public void hours_21() { test("hours('16:24:24-08:00'^^xsd:time)", "16"); } - @Test public void hours_dur_01() { test("hours('P1Y2M3DT4H5M6S'^^xsd:duration)", "4"); } + @Test public void hours_dur_01() { test("hours('P1Y2M3DT4H5M6S'^^xsd:duration)", "4"); } // MINUTES - @Test public void minutes_01() { test("minutes('2010-12-24T16:24:01.123'^^xsd:dateTime)", "24"); } - @Test - public void minutes_02() { assertThrows(ExprEvalException.class, ()-> test("minutes('2010-12-24'^^xsd:date)", "") ); } - @Test public void minutes_03() { test("minutes('16:24:01'^^xsd:time)", "24"); } + @Test public void minutes_01() { test("minutes('2010-12-24T16:24:01.123'^^xsd:dateTime)", "24"); } + @Test public void minutes_02() { assertThrows(ExprEvalException.class, ()-> test("minutes('2010-12-24'^^xsd:date)", "") ); } + @Test public void minutes_03() { test("minutes('16:24:01'^^xsd:time)", "24"); } - @Test public void minutes_10() { test("minutes('2010-12-24T16:24:01.123Z'^^xsd:dateTime)", "24"); } - @Test public void minutes_11() { test("minutes('16:24:01.1Z'^^xsd:time)", "24"); } + @Test public void minutes_10() { test("minutes('2010-12-24T16:24:01.123Z'^^xsd:dateTime)", "24"); } + @Test public void minutes_11() { test("minutes('16:24:01.1Z'^^xsd:time)", "24"); } - @Test public void minutes_20() { test("minutes('2010-12-24T16:24:01.123-08:00'^^xsd:dateTime)", "24"); } - @Test public void minutes_21() { test("minutes('16:24:01.01-08:00'^^xsd:time)", "24"); } + @Test public void minutes_20() { test("minutes('2010-12-24T16:24:01.123-08:00'^^xsd:dateTime)", "24"); } + @Test public void minutes_21() { test("minutes('16:24:01.01-08:00'^^xsd:time)", "24"); } - @Test public void minutes_dur_01() { test("minutes('P1Y2M3DT4H5M6S'^^xsd:duration)", "5"); } + @Test public void minutes_dur_01() { test("minutes('P1Y2M3DT4H5M6S'^^xsd:duration)", "5"); } // SECONDS - @Test public void seconds_01() { test("seconds('2010-12-24T16:24:01.123'^^xsd:dateTime)", "01.123"); } + @Test public void seconds_01() { test("seconds('2010-12-24T16:24:01.123'^^xsd:dateTime)", "01.123"); } @Test - public void seconds_02() { assertThrows(ExprEvalException.class, ()-> test("seconds('2010-12-24'^^xsd:date)", "") ); } - @Test public void seconds_03() { test("seconds('16:24:01'^^xsd:time)", "'01'^^xsd:decimal"); } + public void seconds_02() { assertThrows(ExprEvalException.class, ()-> test("seconds('2010-12-24'^^xsd:date)", "") ); } + @Test public void seconds_03() { test("seconds('16:24:01'^^xsd:time)", "'01'^^xsd:decimal"); } - @Test public void seconds_10() { test("seconds('2010-12-24T16:24:31.123Z'^^xsd:dateTime)", "31.123"); } - @Test public void seconds_11() { test("seconds('16:24:01.1Z'^^xsd:time)", "'01.1'^^xsd:decimal"); } + @Test public void seconds_10() { test("seconds('2010-12-24T16:24:31.123Z'^^xsd:dateTime)", "31.123"); } + @Test public void seconds_11() { test("seconds('16:24:01.1Z'^^xsd:time)", "'01.1'^^xsd:decimal"); } - @Test public void seconds_20() { test("seconds('2010-12-24T16:24:35.123-08:00'^^xsd:dateTime)", "35.123"); } - @Test public void seconds_21() { test("seconds('16:24:01.01-08:00'^^xsd:time)", "'01.01'^^xsd:decimal"); } + @Test public void seconds_20() { test("seconds('2010-12-24T16:24:35.123-08:00'^^xsd:dateTime)", "35.123"); } + @Test public void seconds_21() { test("seconds('16:24:01.01-08:00'^^xsd:time)", "'01.01'^^xsd:decimal"); } - @Test public void seconds_dur_01() { test("seconds('P1Y2M3DT4H5M6S'^^xsd:duration)", "'6.0'^^xsd:decimal"); } + @Test public void seconds_dur_01() { test("seconds('P1Y2M3DT4H5M6S'^^xsd:duration)", "'6.0'^^xsd:decimal"); } // TIMEZONE - @Test public void timezone_01() { test("timezone('2010-12-24T16:24:35.123Z'^^xsd:dateTime)", "'PT0S'^^xsd:dayTimeDuration"); } - @Test public void timezone_02() { test("timezone('2010-12-24T16:24:35.123-08:00'^^xsd:dateTime)", "'-PT8H'^^xsd:dayTimeDuration"); } - @Test public void timezone_03() { test("timezone('2010-12-24T16:24:35.123+01:00'^^xsd:dateTime)", "'PT1H'^^xsd:dayTimeDuration"); } - @Test public void timezone_04() { test("timezone('2010-12-24T16:24:35.123-00:00'^^xsd:dateTime)", "'-PT0S'^^xsd:dayTimeDuration"); } - @Test public void timezone_05() { test("timezone('2010-12-24T16:24:35.123+00:00'^^xsd:dateTime)", "'PT0S'^^xsd:dayTimeDuration"); } + @Test public void timezone_01() { test("timezone('2010-12-24T16:24:35.123Z'^^xsd:dateTime)", "'PT0S'^^xsd:dayTimeDuration"); } + @Test public void timezone_02() { test("timezone('2010-12-24T16:24:35.123-08:00'^^xsd:dateTime)", "'-PT8H'^^xsd:dayTimeDuration"); } + @Test public void timezone_03() { test("timezone('2010-12-24T16:24:35.123+01:00'^^xsd:dateTime)", "'PT1H'^^xsd:dayTimeDuration"); } + @Test public void timezone_04() { test("timezone('2010-12-24T16:24:35.123-00:00'^^xsd:dateTime)", "'-PT0S'^^xsd:dayTimeDuration"); } + @Test public void timezone_05() { test("timezone('2010-12-24T16:24:35.123+00:00'^^xsd:dateTime)", "'PT0S'^^xsd:dayTimeDuration"); } - @Test - public void timezone_09() { assertThrows(ExprEvalException.class, ()-> test("timezone('2010-12-24T16:24:35'^^xsd:dateTime)", "'PT0S'^^xsd:dayTimeDuration") ); } - @Test - public void timezone_10() { assertThrows(ExprEvalException.class, ()-> test("timezone(2010)", "'PT0S'^^xsd:dayTimeDuration") ); } - @Test - public void timezone_11() { assertThrows(ExprEvalException.class, ()-> test("timezone('2010-junk'^^xsd:gYear)", "'PT0S'^^xsd:dayTimeDuration") ); } + @Test public void timezone_09() { assertThrows(ExprEvalException.class, ()-> test("timezone('2010-12-24T16:24:35'^^xsd:dateTime)", "'PT0S'^^xsd:dayTimeDuration") ); } + @Test public void timezone_10() { assertThrows(ExprEvalException.class, ()-> test("timezone(2010)", "'PT0S'^^xsd:dayTimeDuration") ); } + @Test public void timezone_11() { assertThrows(ExprEvalException.class, ()-> test("timezone('2010-junk'^^xsd:gYear)", "'PT0S'^^xsd:dayTimeDuration") ); } // General "adjust-to-timezone" @Test public void adjust_1() { @@ -503,40 +496,32 @@ public class TestFunctions2 // TZ - @Test public void tz_01() { test("tz('2010-12-24T16:24:35.123Z'^^xsd:dateTime)", "'Z'"); } - @Test public void tz_02() { test("tz('2010-12-24T16:24:35.123-08:00'^^xsd:dateTime)", "'-08:00'"); } - @Test public void tz_03() { test("tz('2010-12-24T16:24:35.123+01:00'^^xsd:dateTime)", "'+01:00'"); } - @Test public void tz_04() { test("tz('2010-12-24T16:24:35.123-00:00'^^xsd:dateTime)", "'-00:00'"); } - @Test public void tz_05() { test("tz('2010-12-24T16:24:35.123+00:00'^^xsd:dateTime)", "'+00:00'"); } - @Test public void tz_06() { test("tz('2010-12-24T16:24:35.123'^^xsd:dateTime)", "''"); } + @Test public void tz_01() { test("tz('2010-12-24T16:24:35.123Z'^^xsd:dateTime)", "'Z'"); } + @Test public void tz_02() { test("tz('2010-12-24T16:24:35.123-08:00'^^xsd:dateTime)", "'-08:00'"); } + @Test public void tz_03() { test("tz('2010-12-24T16:24:35.123+01:00'^^xsd:dateTime)", "'+01:00'"); } + @Test public void tz_04() { test("tz('2010-12-24T16:24:35.123-00:00'^^xsd:dateTime)", "'-00:00'"); } + @Test public void tz_05() { test("tz('2010-12-24T16:24:35.123+00:00'^^xsd:dateTime)", "'+00:00'"); } + @Test public void tz_06() { test("tz('2010-12-24T16:24:35.123'^^xsd:dateTime)", "''"); } - @Test - public void tz_10() { assertThrows(ExprEvalException.class, ()-> test("tz(2010)", "''") ); } - @Test - public void tz_11() { assertThrows(ExprEvalException.class, ()-> test("tz('2010-junk'^^xsd:gYear)", "''") ); } + @Test public void tz_10() { assertThrows(ExprEvalException.class, ()-> test("tz(2010)", "''") ); } + @Test public void tz_11() { assertThrows(ExprEvalException.class, ()-> test("tz('2010-junk'^^xsd:gYear)", "''") ); } // NOW //@Test public void now_01() { test("now() > '2010-12-24T16:24:35.123-08:00'^^xsd:dateTime", "true"); } - // MD5 - @Test public void md5_01() { test("md5('abcd')","'e2fc714c4727ee9395f324cd2e7f331f'"); } - @Test public void md5_02() { test("md5('abcd'^^xsd:string)","'e2fc714c4727ee9395f324cd2e7f331f'"); } - @Test - public void md5_03() { assertThrows(ExprEvalException.class, ()-> test("md5('abcd'@en)","'e2fc714c4727ee9395f324cd2e7f331f'") ); } - @Test - public void md5_04() { assertThrows(ExprEvalException.class, ()-> test("md5(1234)","'e2fc714c4727ee9395f324cd2e7f331f'") ); } + @Test public void md5_01() { test("md5('abcd')","'e2fc714c4727ee9395f324cd2e7f331f'"); } + @Test public void md5_02() { test("md5('abcd'^^xsd:string)","'e2fc714c4727ee9395f324cd2e7f331f'"); } + @Test public void md5_03() { assertThrows(ExprEvalException.class, ()-> test("md5('abcd'@en)","'e2fc714c4727ee9395f324cd2e7f331f'") ); } + @Test public void md5_04() { assertThrows(ExprEvalException.class, ()-> test("md5(1234)","'e2fc714c4727ee9395f324cd2e7f331f'") ); } // SHA1 + @Test public void sha1_01() { test("sha1('abcd')","'81fe8bfe87576c3ecb22426f8e57847382917acf'"); } + @Test public void sha1_02() { test("sha1('abcd'^^xsd:string)","'81fe8bfe87576c3ecb22426f8e57847382917acf'"); } + @Test public void sha1_03() { assertThrows(ExprEvalException.class, ()-> test("sha1('abcd'@en)","'81fe8bfe87576c3ecb22426f8e57847382917acf'") ); } + @Test public void sha1_04() { assertThrows(ExprEvalException.class, ()-> test("sha1(123)","'81fe8bfe87576c3ecb22426f8e57847382917acf'") ); } - @Test public void sha1_01() { test("sha1('abcd')","'81fe8bfe87576c3ecb22426f8e57847382917acf'"); } - @Test public void sha1_02() { test("sha1('abcd'^^xsd:string)","'81fe8bfe87576c3ecb22426f8e57847382917acf'"); } - @Test - public void sha1_03() { assertThrows(ExprEvalException.class, ()-> test("sha1('abcd'@en)","'81fe8bfe87576c3ecb22426f8e57847382917acf'") ); } - @Test - public void sha1_04() { assertThrows(ExprEvalException.class, ()-> test("sha1(123)","'81fe8bfe87576c3ecb22426f8e57847382917acf'") ); } - - // SHA224 +// // SHA224 // @Test public void sha224_01() { test("sha224('abcd')","'e2fc714c4727ee9395f324cd2e7f331f'"); } // // @Test @@ -550,49 +535,43 @@ public class TestFunctions2 // SHA256 - @Test public void sha256_01() { test("sha256('abcd')","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'"); } - - @Test public void sha256_02() { test("sha256('abcd'^^xsd:string)","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'"); } - - @Test - public void sha256_03() { assertThrows(ExprEvalException.class, ()-> test("sha256('abcd'@en)","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'") ); } - - @Test - public void sha256_04() { assertThrows(ExprEvalException.class, ()-> test("sha256(<uri>)","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'") ); } + @Test public void sha256_01() { test("sha256('abcd')","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'"); } + @Test public void sha256_02() { test("sha256('abcd'^^xsd:string)","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'"); } + @Test public void sha256_03() { assertThrows(ExprEvalException.class, ()-> test("sha256('abcd'@en)","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'") ); } + @Test public void sha256_04() { assertThrows(ExprEvalException.class, ()-> test("sha256(<uri>)","'88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589'") ); } // SHA384 - @Test public void sha384_01() { test("sha384('abcd')","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'"); } - - - @Test public void sha384_02() { test("sha384('abcd'^^xsd:string)","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'"); } - - @Test - public void sha384_03() { assertThrows(ExprEvalException.class, ()-> test("sha384('abcd'@en)","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'") ); } - - @Test - public void sha384_04() { assertThrows(ExprEvalException.class, ()-> test("sha384(123.45)","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'") ); } + @Test public void sha384_01() { test("sha384('abcd')","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'"); } + @Test public void sha384_02() { test("sha384('abcd'^^xsd:string)","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'"); } + @Test public void sha384_03() { assertThrows(ExprEvalException.class, ()-> test("sha384('abcd'@en)","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'") ); } + @Test public void sha384_04() { assertThrows(ExprEvalException.class, ()-> test("sha384(123.45)","'1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b'") ); } // SHA512 - @Test public void sha512_01() { test("sha512('abcd')","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'"); } - - @Test public void sha512_02() { test("sha512('abcd'^^xsd:string)","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'"); } - - @Test - public void sha512_03() { assertThrows(ExprEvalException.class, ()-> test("md5('abcd'@en)","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'") ); } - - @Test - public void sha512_04() { assertThrows(ExprEvalException.class, ()-> test("md5(0.0e0)","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'") ); } + @Test public void sha512_01() { test("sha512('abcd')","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'"); } + @Test public void sha512_02() { test("sha512('abcd'^^xsd:string)","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'"); } + @Test public void sha512_03() { assertThrows(ExprEvalException.class, ()-> test("md5('abcd'@en)","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'") ); } + @Test public void sha512_04() { assertThrows(ExprEvalException.class, ()-> test("md5(0.0e0)","'d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f'") ); } // -------- private static PrefixMapping pmap = ARQConstants.getGlobalPrefixMap(); - private static void test(String string, String result) { - Expr expr = ExprUtils.parse(string, pmap); + private static void test(String expressionStr, String result) { + Expr expr = ExprUtils.parse(expressionStr, pmap); NodeValue nv = expr.eval(null, new FunctionEnvBase()); Node r = NodeFactoryExtra.parseNode(result); NodeValue nvr = NodeValue.makeNode(r); + // Check datatypes. + RDFDatatype dtActual = nv.asNode().getLiteralDatatype(); + RDFDatatype dtExpected = nvr.asNode().getLiteralDatatype(); + assertEquals(dtExpected, dtActual, "Differing datatpes"); + + // Same term works for NaNs + if ( nv.asNode().sameTermAs(nvr.asNode()) ) + return; + + // Not NaNs! assertTrue(NodeValue.sameValueAs(nvr, nv), "Not same value: Expected: " + nvr + " : Actual = " + nv); // test result must be lexical form exact. assertEquals(r, nv.asNode()); diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java index 971ac7b58b..894fc3a444 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestXSDFuncOp.java @@ -805,6 +805,104 @@ public class TestXSDFuncOp { assertEquals(2d, r.getDouble(), accuracyExact_D, "Wrong result"); } + @Test public void testRoundDouble1() { + NodeValue nv = NodeValue.makeDouble(1.23d); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r.isDouble(), "Not a double: "+r); + assertTrue(r instanceof NodeValueDouble, "Not a NodeValueDouble: "+r); + assertEquals(1d, r.getDouble(), 0d, "Wrong result"); + } + + @Test public void testRoundDouble2() { + NodeValue nv = NodeValue.makeDouble(0d); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r.isDouble(), "Not a double: "+r); + assertTrue(r instanceof NodeValueDouble, "Not a NodeValueDouble: "+r); + assertEquals(0.0d, r.getDouble(), 0d, "Wrong result"); + } + + @Test public void testRoundDouble3() { + NodeValue nv = NodeValue.makeDouble(-0d); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r.isDouble(), "Not a double: "+r); + assertTrue(r instanceof NodeValueDouble, "Not a NodeValueDouble: "+r); + assertEquals(-0.0d, r.getDouble(), 0d, "Wrong result"); + } + + @Test public void testRoundDouble4() { + NodeValue nv = NodeValue.makeDouble(Double.NaN); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(XSDNumUtils.isNaN(r)); + } + + @Test public void testRoundDouble5() { + NodeValue nv = NodeValue.makeDouble(Double.POSITIVE_INFINITY); + NodeValue r = XSDFuncOp.round(nv); + assertEquals(r.getDouble(), Double.POSITIVE_INFINITY); + } + + @Test public void testRoundDouble6() { + NodeValue nv = NodeValue.makeDouble(Double.NEGATIVE_INFINITY); + NodeValue r = XSDFuncOp.round(nv); + assertEquals(r.getDouble(), Double.NEGATIVE_INFINITY); + } + + @Test public void testRoundFloat1() { + NodeValue nv = NodeValue.makeFloat(1.23f); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r.isFloat(), "Not a float: "+r); + assertTrue(r instanceof NodeValueFloat, "Not a NodeValueFloat: "+r); + assertEquals(1f, r.getFloat(), 0f, "Wrong result"); + } + + @Test public void testRoundFloat2() { + NodeValue nv = NodeValue.makeFloat(0f); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r.isFloat(), "Not a float: "+r); + assertTrue(r instanceof NodeValueFloat, "Not a NodeValueFloat: "+r); + assertEquals(0.0f, r.getFloat(), 0f, "Wrong result"); + } + + @Test public void testRoundFloat3() { + NodeValue nv = NodeValue.makeFloat(-0f); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r.isFloat(), "Not a float: "+r); + assertTrue(r instanceof NodeValueFloat, "Not a NodeValueFloat: "+r); + assertEquals(-0.0f, r.getFloat(), 0f, "Wrong result"); + } + + @Test public void testRoundFloat4() { + NodeValue nv = NodeValue.makeFloat(Float.NaN); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(XSDNumUtils.isNaN(r)); + } + + @Test public void testRoundFloat5() { + NodeValue nv = NodeValue.makeFloat(Float.POSITIVE_INFINITY); + NodeValue r = XSDFuncOp.round(nv); + assertEquals(r.getFloat(), Float.POSITIVE_INFINITY); + } + + @Test public void testRoundFloat6() { + NodeValue nv = NodeValue.makeFloat(Float.NEGATIVE_INFINITY); + NodeValue r = XSDFuncOp.round(nv); + assertEquals(r.getFloat(), Double.NEGATIVE_INFINITY); + } + + @Test public void testRound1() { + NodeValue nv = NodeValue.makeDecimal(1.23); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r instanceof NodeValueDecimal, "Not a NodeValueDecimal: "+r); + assertEquals(new BigDecimal("1"), r.getDecimal(), "Wrong result"); + } + + @Test public void testRound2() { + NodeValue nv = NodeValue.makeDecimal(-1.23); + NodeValue r = XSDFuncOp.round(nv); + assertTrue(r instanceof NodeValueDecimal, "Not a NodeValueDecimal: "+r); + assertEquals(new BigDecimal("-1"), r.getDecimal(), "Wrong result"); + } + @Test public void testCeiling1() { NodeValue nv = NodeValue.makeDecimal(2.6); NodeValue r = XSDFuncOp.ceiling(nv);
