/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jena.sparql.function.user; import java.util.ArrayList; import java.util.List; import org.apache.jena.sparql.core.Var ; import org.apache.jena.sparql.engine.binding.BindingFactory ; import org.apache.jena.sparql.expr.* ; import org.apache.jena.sparql.expr.nodevalue.NodeValueBoolean ; import org.apache.jena.sparql.expr.nodevalue.NodeValueDouble ; import org.apache.jena.sparql.expr.nodevalue.NodeValueInteger ; import org.apache.jena.sparql.function.FunctionEnvBase ; import org.apache.jena.sparql.function.user.UserDefinedFunction ; import org.apache.jena.sparql.function.user.UserDefinedFunctionDefinition ; import org.apache.jena.sparql.function.user.UserDefinedFunctionFactory ; import org.apache.jena.sparql.sse.builders.ExprBuildException ; import org.apache.jena.sparql.util.NodeFactoryExtra ; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; /** * Test for checking that functions are appropriately expanded when supplied with actual arguments * and the default behavior of not preserving dependencies is enabled */ public class TestFunctionExpansion { @BeforeClass public static void setup() { UserDefinedFunctionFactory.getFactory().clear(); UserDefinedFunctionFactory.getFactory().setPreserveDependencies(false); } @AfterClass public static void teardown() { UserDefinedFunctionFactory.getFactory().clear(); UserDefinedFunctionFactory.getFactory().setPreserveDependencies(false); } @Test public void test_function_expansion_01() { Expr e = new ExprVar("x"); UserDefinedFunctionFactory.getFactory().add("http://example/simple", e, new ArrayList<>(e.getVarsMentioned())); UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/simple"); f.build("http://example/simple", new ExprList(new NodeValueBoolean(true))); Expr actual = f.getActualExpr(); Assert.assertFalse(e.equals(actual)); Assert.assertEquals(0, actual.getVarsMentioned().size()); Assert.assertEquals(new NodeValueBoolean(true), actual); } @Test public void test_function_expansion_02() { Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x")); UserDefinedFunctionFactory.getFactory().add("http://example/square", e, new ArrayList<>(e.getVarsMentioned())); UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/square"); f.build("http://example/square", new ExprList(new NodeValueInteger(3))); Expr actual = f.getActualExpr(); Assert.assertFalse(e.equals(actual)); Assert.assertEquals(0, actual.getVarsMentioned().size()); Assert.assertEquals(new E_Multiply(new NodeValueInteger(3), new NodeValueInteger(3)), actual); } @Test public void test_function_expansion_03() { Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("y")); List<Var> defArgs = new ArrayList<>(); defArgs.add(Var.alloc("x")); defArgs.add(Var.alloc("y")); UserDefinedFunctionFactory.getFactory().add("http://example/square", e, defArgs); UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/square"); ExprList args = new ExprList(); args.add(new NodeValueInteger(3)); args.add(new NodeValueInteger(4)); f.build("http://example/square", args); Expr actual = f.getActualExpr(); Assert.assertFalse(e.equals(actual)); Assert.assertEquals(0, actual.getVarsMentioned().size()); Assert.assertEquals(new E_Multiply(new NodeValueInteger(3), new NodeValueInteger(4)), actual); } @Test public void test_function_expansion_04() { Expr square = new E_Multiply(new ExprVar("x"), new ExprVar("x")); UserDefinedFunctionFactory.getFactory().add("http://example/square", square, new ArrayList<>(square.getVarsMentioned())); //Test that with preserveDependencies set to false (the default) that the definition of cube is actually //expanded to include the definition of square Expr cube = new E_Multiply(new E_Function("http://example/square", new ExprList(new ExprVar("x"))), new ExprVar("x")); UserDefinedFunctionFactory.getFactory().add("http://example/cube", cube, new ArrayList<>(cube.getVarsMentioned())); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/cube"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Multiply); E_Multiply m = (E_Multiply)base; Assert.assertTrue(m.getArg1() instanceof E_Multiply); Assert.assertTrue(m.getArg2() instanceof ExprVar); Assert.assertEquals(1, base.getVarsMentioned().size()); } @Test public void test_function_expansion_05() { Expr square = new E_Multiply(new ExprVar("x"), new ExprVar("x")); UserDefinedFunctionFactory.getFactory().add("http://example/square", square, new ArrayList<>(square.getVarsMentioned())); //Test that with preserveDependencies set to false (the default) that the definition of cube is actually //expanded to include the definition of square Expr cube = new E_Multiply(new E_Function("http://example/square", new ExprList(new ExprVar("y"))), new ExprVar("y")); UserDefinedFunctionFactory.getFactory().add("http://example/cube", cube, new ArrayList<>(cube.getVarsMentioned())); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/cube"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Multiply); E_Multiply m = (E_Multiply)base; Assert.assertTrue(m.getArg1() instanceof E_Multiply); Assert.assertTrue(m.getArg2() instanceof ExprVar); Assert.assertEquals(1, base.getVarsMentioned().size()); } @Test public void test_function_expansion_06() { Expr takeaway = new E_Subtract(new ExprVar("x"), new ExprVar("y")); List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); UserDefinedFunctionFactory.getFactory().add("http://example/takeaway", takeaway, args); //Test that with preserveDependencies set to false (the default) that the definition is expanded appropriately ExprList numArgs = new ExprList(); numArgs.add(new NodeValueInteger(1)); numArgs.add(new NodeValueDouble(2.3)); Expr test = new E_Function("http://example/takeaway", numArgs); UserDefinedFunctionFactory.getFactory().add("http://example/test", test, new ArrayList<Var>()); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/test"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Subtract); E_Subtract subtract = (E_Subtract)base; Assert.assertTrue(subtract.getArg1() instanceof NodeValueInteger); Assert.assertTrue(subtract.getArg2() instanceof NodeValueDouble); } @Test public void test_function_expansion_07() { Expr takeaway = new E_Subtract(new ExprVar("x"), new ExprVar("y")); List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); UserDefinedFunctionFactory.getFactory().add("http://example/takeaway", takeaway, args); //Test that with preserveDependencies set to false (the default) that the definition is expanded appropriately ExprList numArgs = new ExprList(); numArgs.add(new NodeValueDouble(2.3)); numArgs.add(new NodeValueInteger(1)); Expr test = new E_Function("http://example/takeaway", numArgs); UserDefinedFunctionFactory.getFactory().add("http://example/test", test, new ArrayList<Var>()); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/test"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Subtract); E_Subtract subtract = (E_Subtract)base; Assert.assertTrue(subtract.getArg1() instanceof NodeValueDouble); Assert.assertTrue(subtract.getArg2() instanceof NodeValueInteger); } @Test public void test_function_expansion_08() { Expr takeaway = new E_Subtract(new ExprVar("x"), new ExprVar("y")); List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); UserDefinedFunctionFactory.getFactory().add("http://example/takeaway", takeaway, args); //Test that with preserveDependencies set to false (the default) that the definition is expanded appropriately ExprList altArgs = new ExprList(); altArgs.add(new ExprVar("a")); altArgs.add(new ExprVar("b")); ArrayList<Var> defArgs = new ArrayList<>(); defArgs.add(Var.alloc("a")); defArgs.add(Var.alloc("b")); Expr test = new E_Function("http://example/takeaway", altArgs); UserDefinedFunctionFactory.getFactory().add("http://example/test", test, defArgs); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/test"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Subtract); E_Subtract subtract = (E_Subtract)base; Assert.assertTrue(subtract.getArg1() instanceof ExprVar); Assert.assertTrue(subtract.getArg2() instanceof ExprVar); Assert.assertEquals(subtract.getArg1().getVarName(), "a"); Assert.assertEquals(subtract.getArg2().getVarName(), "b"); } @Test public void test_function_expansion_09() { Expr takeaway = new E_Subtract(new ExprVar("x"), new ExprVar("y")); List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); UserDefinedFunctionFactory.getFactory().add("http://example/takeaway", takeaway, args); //Test that with preserveDependencies set to false (the default) that the definition is expanded appropriately ExprList altArgs = new ExprList(); altArgs.add(new ExprVar("b")); altArgs.add(new ExprVar("a")); ArrayList<Var> defArgs = new ArrayList<>(); defArgs.add(Var.alloc("a")); defArgs.add(Var.alloc("b")); Expr test = new E_Function("http://example/takeaway", altArgs); UserDefinedFunctionFactory.getFactory().add("http://example/test", test, defArgs); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/test"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Subtract); E_Subtract subtract = (E_Subtract)base; Assert.assertTrue(subtract.getArg1() instanceof ExprVar); Assert.assertTrue(subtract.getArg2() instanceof ExprVar); Assert.assertEquals(subtract.getArg1().getVarName(), "b"); Assert.assertEquals(subtract.getArg2().getVarName(), "a"); } @Test public void test_function_expansion_10() { Expr single = new ExprVar("x"); UserDefinedFunctionFactory.getFactory().add("http://example/single", single, new ArrayList<>(single.getVarsMentioned())); //Test that with preserveDependencies set to false (the default) that the definition is expanded appropriately //when the outer function has differing numbers of arguments List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); Expr add = new E_Add(new E_Function("http://example/single", new ExprList(new ExprVar("x"))), new ExprVar("y")); UserDefinedFunctionFactory.getFactory().add("http://example/add", add, args); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/add"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Add); E_Add actual = (E_Add)base; Assert.assertTrue(actual.getArg1() instanceof ExprVar); Assert.assertTrue(actual.getArg2() instanceof ExprVar); Assert.assertEquals("x", actual.getArg1().getVarName()); Assert.assertEquals("y", actual.getArg2().getVarName()); } @Test public void test_function_expansion_11() { Expr single = new ExprVar("x"); UserDefinedFunctionFactory.getFactory().add("http://example/single", single, new ArrayList<>(single.getVarsMentioned())); //Test that with preserveDependencies set to false (the default) that the definition is expanded appropriately //when the outer function has differing numbers of arguments List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); Expr add = new E_Add(new E_Function("http://example/single", new ExprList(new ExprVar("y"))), new ExprVar("y")); UserDefinedFunctionFactory.getFactory().add("http://example/add", add, args); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/add"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Add); E_Add actual = (E_Add)base; Assert.assertTrue(actual.getArg1() instanceof ExprVar); Assert.assertTrue(actual.getArg2() instanceof ExprVar); Assert.assertEquals("y", actual.getArg1().getVarName()); Assert.assertEquals("y", actual.getArg2().getVarName()); } @Test public void test_function_expansion_12() { Expr takeaway = new E_Subtract(new ExprVar("x"), new ExprVar("y")); List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); UserDefinedFunctionFactory.getFactory().add("http://example/takeaway", takeaway, args); //Test that with preserveDependencies set to false (the default) that the definition is expanded appropriately ExprList altArgs = new ExprList(); altArgs.add(new ExprVar("a")); altArgs.add(new ExprVar("a")); ArrayList<Var> defArgs = new ArrayList<>(); defArgs.add(Var.alloc("a")); defArgs.add(Var.alloc("b")); Expr test = new E_Function("http://example/takeaway", altArgs); UserDefinedFunctionFactory.getFactory().add("http://example/test", test, defArgs); UserDefinedFunctionDefinition def = UserDefinedFunctionFactory.getFactory().get("http://example/test"); Expr base = def.getBaseExpr(); Assert.assertTrue(base instanceof E_Subtract); E_Subtract subtract = (E_Subtract)base; Assert.assertTrue(subtract.getArg1() instanceof ExprVar); Assert.assertTrue(subtract.getArg2() instanceof ExprVar); Assert.assertEquals(subtract.getArg1().getVarName(), "a"); Assert.assertEquals(subtract.getArg2().getVarName(), "a"); } @Test public void test_function_expansion_13() { Expr square = new E_Multiply(new ExprVar("x"), new ExprVar("x")); UserDefinedFunctionFactory.getFactory().add("http://example/square", square, new ArrayList<>(square.getVarsMentioned())); //This test illustrates that if we change the definition of square and call our function again we always //get the same result with dependencies not preserved because even though the definition of the dependent function //can change the definition of our function is fully expanded when first defined Expr cube = new E_Multiply(new E_Function("http://example/square", new ExprList(new ExprVar("x"))), new ExprVar("x")); UserDefinedFunctionFactory.getFactory().add("http://example/cube", cube, new ArrayList<>(cube.getVarsMentioned())); UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/cube"); f.build("http://example/cube", new ExprList(new NodeValueInteger(2))); Expr actual = f.getActualExpr(); NodeValue result = actual.eval(BindingFactory.create(), FunctionEnvBase.createTest()); Assert.assertEquals(8, NodeFactoryExtra.nodeToInt(result.asNode())); //Change the definition of the function we depend on //This has no effect with preserveDependencies set to false (the default) since we fully expanded the call to the dependent //function when our outer function was defined square = new ExprVar("x"); UserDefinedFunctionFactory.getFactory().add("http://example/square", square, new ArrayList<>(square.getVarsMentioned())); f.build("http://example/cube", new ExprList(new NodeValueInteger(2))); actual = f.getActualExpr(); result = actual.eval(BindingFactory.create(), FunctionEnvBase.createTest()); Assert.assertEquals(8, NodeFactoryExtra.nodeToInt(result.asNode())); } @Test(expected=ExprBuildException.class) public void test_function_expansion_bad_01() { List<Var> args = new ArrayList<>(); args.add(Var.alloc("x")); args.add(Var.alloc("y")); Expr add = new E_Add(new ExprVar("x"), new ExprVar("y")); //It's an error to use a variable which is not mentioned in the argument list UserDefinedFunctionFactory.getFactory().add("http://example/add", add, new ArrayList<Var>()); } @Test(expected=ExprBuildException.class) public void test_function_expansion_bad_02() { Expr single = new ExprVar("x"); UserDefinedFunctionFactory.getFactory().add("http://example/single", single, new ArrayList<>(single.getVarsMentioned())); //It's an error to use a variable which is not mentioned in the argument list, even in a call to a dependent function Expr test = new E_Function("http://example/single", new ExprList(new ExprVar("x"))); UserDefinedFunctionFactory.getFactory().add("http://example/test", test, new ArrayList<Var>()); } }