This is an automated email from the ASF dual-hosted git repository. afs pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
commit 0514145c9cdebae0bc944079509ce85b419543c9 Author: Andy Seaborne <[email protected]> AuthorDate: Thu Oct 1 19:23:31 2026 +0100 GH-4284: VarUtils.addVarsFromTriplePath --- .../java/org/apache/jena/sparql/util/VarUtils.java | 2 + .../java/org/apache/jena/util/TS_UtilsARQ.java | 3 +- .../java/org/apache/jena/util/TestVarUtils.java | 342 +++++++++++++++++++++ 3 files changed, 346 insertions(+), 1 deletion(-) diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/util/VarUtils.java b/jena-arq/src/main/java/org/apache/jena/sparql/util/VarUtils.java index 41b61050fd..ad4234cadc 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/util/VarUtils.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/util/VarUtils.java @@ -52,6 +52,8 @@ public class VarUtils { public static void addVarsFromTriplePath(Collection<Var> acc, TriplePath tpath) { addVar(acc, tpath.getSubject()); + if ( tpath.isTriple() ) + addVar(acc, tpath.getPredicate()); addVar(acc, tpath.getObject()); } diff --git a/jena-arq/src/test/java/org/apache/jena/util/TS_UtilsARQ.java b/jena-arq/src/test/java/org/apache/jena/util/TS_UtilsARQ.java index a91383637a..9de3134e37 100644 --- a/jena-arq/src/test/java/org/apache/jena/util/TS_UtilsARQ.java +++ b/jena-arq/src/test/java/org/apache/jena/util/TS_UtilsARQ.java @@ -26,7 +26,8 @@ import org.junit.platform.suite.api.Suite; @Suite @SelectClasses({ - TestNodeUtils.class + TestNodeUtils.class, + TestVarUtils.class }) public class TS_UtilsARQ {} diff --git a/jena-arq/src/test/java/org/apache/jena/util/TestVarUtils.java b/jena-arq/src/test/java/org/apache/jena/util/TestVarUtils.java new file mode 100644 index 0000000000..5e057db330 --- /dev/null +++ b/jena-arq/src/test/java/org/apache/jena/util/TestVarUtils.java @@ -0,0 +1,342 @@ +/* + * 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 + * + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.apache.jena.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.graph.Triple; +import org.apache.jena.sparql.core.BasicPattern; +import org.apache.jena.sparql.core.Quad; +import org.apache.jena.sparql.core.QuadPattern; +import org.apache.jena.sparql.core.TriplePath; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.path.Path; +import org.apache.jena.sparql.pfunction.PropFuncArg; +import org.apache.jena.sparql.sse.SSE; +import org.apache.jena.sparql.util.VarUtils; + +public class TestVarUtils { + + private static final Node g = SSE.parseNode(":g"); + private static final Node s = SSE.parseNode(":s"); + private static final Node p = SSE.parseNode(":p"); + private static final Node o = SSE.parseNode(":o"); + + private static final Var varG = Var.alloc("g"); + private static final Var varS = Var.alloc("s"); + private static final Var varP = Var.alloc("p"); + private static final Var varO = Var.alloc("o"); + private static final Var varX = Var.alloc("x"); + + private static Set<Var> vars(Var...vars) { + return new LinkedHashSet<>(Arrays.asList(vars)); + } + + // -- getVars(Triple) + + @Test public void getVars_triple_01() { + Triple triple = SSE.parseTriple("(:s :p :o)"); + assertEquals(vars(), VarUtils.getVars(triple)); + } + + @Test public void getVars_triple_02() { + Triple triple = SSE.parseTriple("(?s ?p ?o)"); + assertEquals(vars(varS, varP, varO), VarUtils.getVars(triple)); + } + + @Test public void getVars_triple_03() { + Triple triple = SSE.parseTriple("(?s :p ?o)"); + assertEquals(vars(varS, varO), VarUtils.getVars(triple)); + } + + // Same variable twice - a set, so once. + @Test public void getVars_triple_04() { + Triple triple = SSE.parseTriple("(?x :p ?x)"); + assertEquals(vars(varX), VarUtils.getVars(triple)); + } + + // Triple terms (RDF 1.2) + @Test public void getVars_triple_05() { + Triple triple = SSE.parseTriple("(?s :p <<( :x :y ?o )>>)"); + assertEquals(vars(varS, varO), VarUtils.getVars(triple)); + } + + @Test public void getVars_triple_06() { + Triple triple = SSE.parseTriple("(:s :p <<( ?x :y <<( :a :b ?o )>> )>>)"); + assertEquals(vars(varX, varO), VarUtils.getVars(triple)); + } + + // -- addVarsFromTriple + + @Test public void addVarsFromTriple_01() { + List<Var> acc = new ArrayList<>(); + Triple triple = SSE.parseTriple("(?s :p ?o)"); + VarUtils.addVarsFromTriple(acc, triple); + assertEquals(List.of(varS, varO), acc); + } + + // A Collection, not a Set - duplicates and accumulation across calls. + @Test public void addVarsFromTriple_02() { + List<Var> acc = new ArrayList<>(); + Triple triple1 = SSE.parseTriple("(?x :p ?x)"); + Triple triple2 = SSE.parseTriple("(?x :p :o)"); + VarUtils.addVarsFromTriple(acc, triple1); + VarUtils.addVarsFromTriple(acc, triple2); + assertEquals(List.of(varX, varX, varX), acc); + } + + @Test public void addVarsFromTriple_03() { + Set<Var> acc = vars(varG); + Triple triple = SSE.parseTriple("(?s :p :o)"); + VarUtils.addVarsFromTriple(acc, triple); + assertEquals(vars(varG, varS), acc); + } + + // -- addVarsFromQuad + + @Test public void addVarsFromQuad_01() { + Set<Var> acc = vars(); + Quad quad = SSE.parseQuad("(:g :s :p :o)"); + VarUtils.addVarsFromQuad(acc, quad); + assertEquals(vars(), acc); + } + + @Test public void addVarsFromQuad_02() { + Set<Var> acc = vars(); + Quad quad = SSE.parseQuad("(?g ?s ?p ?o)"); + VarUtils.addVarsFromQuad(acc, quad); + assertEquals(vars(varG, varS, varP, varO), acc); + } + + @Test public void addVarsFromQuad_03() { + Set<Var> acc = vars(); + VarUtils.addVarsFromQuad(acc, Quad.create(varG, s, p, o)); + assertEquals(vars(varG), acc); + } + + // A quad with no graph - null is skipped, not an error. + @Test public void addVarsFromQuad_04() { + Set<Var> acc = vars(); + VarUtils.addVarsFromQuad(acc, Quad.create(null, varS, p, o)); + assertEquals(vars(varS), acc); + } + + // -- addVarsFromTriplePath + + @Test public void addVarsFromTriplePath_01() { + Set<Var> acc = vars(); + Path path = SSE.parsePath("(path+ :p)"); + VarUtils.addVarsFromTriplePath(acc, new TriplePath(varS, path, varO)); + assertEquals(vars(varS, varO), acc); + } + + @Test public void addVarsFromTriplePath_02() { + Set<Var> acc = vars(); + Path path = SSE.parsePath("(path+ :p)"); + VarUtils.addVarsFromTriplePath(acc, new TriplePath(s, path, o)); + assertEquals(vars(), acc); + } + + // A TriplePath of a triple: the predicate slot is not a path and is not collected. + @Test public void addVarsFromTriplePath_03() { + Set<Var> acc = vars(); + Triple triple = SSE.parseTriple("(?s ?p ?o)"); + TriplePath triplePath = new TriplePath(triple); + VarUtils.addVarsFromTriplePath(acc, triplePath); + assertEquals(vars(varS, varP, varO), acc); + } + + // -- addVar + + @Test public void addVar_01() { + Set<Var> acc = vars(); + VarUtils.addVar(acc, varX); + assertEquals(vars(varX), acc); + } + + // A Node_Variable, not already a Var. + @Test public void addVar_02() { + Set<Var> acc = vars(); + VarUtils.addVar(acc, NodeFactory.createVariable("x")); + assertEquals(vars(varX), acc); + } + + @Test public void addVar_03() { + Set<Var> acc = vars(); + VarUtils.addVar(acc, s); + assertEquals(vars(), acc); + } + + @Test public void addVar_null() { + Set<Var> acc = vars(); + VarUtils.addVar(acc, null); + assertTrue(acc.isEmpty()); + } + + // Node.ANY is not a variable. + @Test public void addVar_any() { + Set<Var> acc = vars(); + VarUtils.addVar(acc, Node.ANY); + assertTrue(acc.isEmpty()); + } + + @Test public void addVar_tripleTerm_01() { + Set<Var> acc = vars(); + Node tripleTerm = SSE.parseNode("<<( ?s :p ?o )>>"); + VarUtils.addVar(acc, tripleTerm); + assertEquals(vars(varS, varO), acc); + } + + @Test public void addVar_tripleTerm_02() { + Set<Var> acc = vars(); + Node tripleTerm = SSE.parseNode("<<( :s :p :o )>>"); + VarUtils.addVar(acc, tripleTerm); + assertEquals(vars(), acc); + } + + // -- addVarNodes + + @Test public void addVarNodes_01() { + Set<Var> acc = vars(); + VarUtils.addVarNodes(acc, List.of(varS, s, varO, o)); + assertEquals(vars(varS, varO), acc); + } + + @Test public void addVarNodes_02() { + Set<Var> acc = vars(); + VarUtils.addVarNodes(acc, List.of()); + assertEquals(vars(), acc); + } + + @Test public void addVarNodes_null() { + Set<Var> acc = vars(); + VarUtils.addVarNodes(acc, null); + assertTrue(acc.isEmpty()); + } + + // -- addVarsTriples + + @Test public void addVarsTriples_01() { + Set<Var> acc = vars(); + List<Triple> triples = List.of(SSE.parseTriple("(?s :p :o)"), SSE.parseTriple("(:s ?p ?o)")); + VarUtils.addVarsTriples(acc, triples); + assertEquals(vars(varS, varP, varO), acc); + } + + @Test public void addVarsTriples_02() { + Set<Var> acc = vars(); + VarUtils.addVarsTriples(acc, List.of()); + assertEquals(vars(), acc); + } + + // -- addVars(acc, BasicPattern) + + @Test public void addVars_bgp_01() { + Set<Var> acc = vars(); + BasicPattern bgp = SSE.parseBGP("(bgp (?s :p :o) (:s ?p ?o))"); + VarUtils.addVars(acc, bgp); + assertEquals(vars(varS, varP, varO), acc); + } + + @Test public void addVars_bgp_02() { + Set<Var> acc = vars(); + VarUtils.addVars(acc, new BasicPattern()); + assertEquals(vars(), acc); + } + + // -- addVars(acc, graphNode, BasicPattern) + + @Test public void addVars_graph_bgp_01() { + Set<Var> acc = vars(); + BasicPattern bgp = SSE.parseBGP("(bgp (?s :p :o))"); + VarUtils.addVars(acc, varG, bgp); + assertEquals(vars(varG, varS), acc); + } + + @Test public void addVars_graph_bgp_02() { + Set<Var> acc = vars(); + BasicPattern bgp = SSE.parseBGP("(bgp (?s :p :o))"); + VarUtils.addVars(acc, g, bgp); + assertEquals(vars(varS), acc); + } + + @Test public void addVars_graph_bgp_03() { + Set<Var> acc = vars(); + BasicPattern bgp = SSE.parseBGP("(bgp (?s :p :o))"); + VarUtils.addVars(acc, null, bgp); + assertEquals(vars(varS), acc); + } + + // -- addVars(acc, QuadPattern) + + @Test public void addVars_quadPattern_01() { + Set<Var> acc = vars(); + QuadPattern quads = new QuadPattern(); + quads.add(Quad.create(varG, s, p, o)); + quads.add(Quad.create(g, varS, p, varO)); + VarUtils.addVars(acc, quads); + assertEquals(vars(varG, varS, varO), acc); + } + + @Test public void addVars_quadPattern_02() { + Set<Var> acc = vars(); + VarUtils.addVars(acc, new QuadPattern()); + assertEquals(vars(), acc); + } + + // -- addVars(acc, PropFuncArg) + + @Test public void addVars_propFuncArg_node_01() { + Set<Var> acc = vars(); + VarUtils.addVars(acc, new PropFuncArg(varX)); + assertEquals(vars(varX), acc); + } + + @Test public void addVars_propFuncArg_node_02() { + Set<Var> acc = vars(); + VarUtils.addVars(acc, new PropFuncArg(s)); + assertEquals(vars(), acc); + } + + @Test public void addVars_propFuncArg_list_01() { + Set<Var> acc = vars(); + VarUtils.addVars(acc, new PropFuncArg(List.of(varS, o, varX))); + assertEquals(vars(varS, varX), acc); + } + + @Test public void addVars_propFuncArg_list_02() { + Set<Var> acc = vars(); + VarUtils.addVars(acc, new PropFuncArg(List.<Node>of())); + assertEquals(vars(), acc); + } +}
