001: /*
002: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: [See end of file]
004: $Id: AbstractTestQuery1.java,v 1.9 2008/01/02 12:08:14 andy_seaborne Exp $
005: */
006:
007: package com.hp.hpl.jena.db.test;
008:
009: import com.hp.hpl.jena.graph.*;
010: import com.hp.hpl.jena.graph.test.*;
011: import com.hp.hpl.jena.graph.query.*;
012: import com.hp.hpl.jena.shared.*;
013: import com.hp.hpl.jena.util.iterator.*;
014: import com.hp.hpl.jena.graph.impl.*;
015: import com.hp.hpl.jena.vocabulary.RDF;
016:
017: import java.util.*;
018: import junit.framework.*;
019:
020: /**
021: Abstract tests for graph query, parameterised on getGraph().
022: @author kers
023: */
024: public abstract class AbstractTestQuery1 extends GraphTestBase {
025: public AbstractTestQuery1(String name) {
026: super (name);
027: }
028:
029: public static TestSuite suite() {
030: return new TestSuite(AbstractTestQuery1.class);
031: }
032:
033: public abstract Graph getGraph();
034:
035: public abstract Graph getGraph(ReificationStyle style);
036:
037: // in the stmt strings below, L indicates a long (object or predicate)
038: // L, if specifed, MUST precede the URI. for the object, a prefix of
039: // U indicates a reference (URI). otherwise, the object is considered
040: // a literal string. if the string begins with R, it is treated as
041: // a reified statement with 4 tokens, where the first is the URI that
042: // reifies the subsequent statement.
043:
044: // the database has the following pattern.
045:
046: protected String[] statementList = {
047:
048: // metadata about properties
049:
050: "Pname Pcard O1", "Psex Pcard O1", "Pdept Pcardmax O5",
051: "Pmgr Pcardmax O1", "Ptitle Pcardmax O5",
052:
053: "Pname Prange Oliteral", "Psex Prange Oliteral",
054: "Pdept Prange Oliteral", "Pmgr Prange Oresource",
055: "Ptitle Prange Oliteral",
056:
057: "S1 Pname Omm", "S1 Psex Omale", "S1 Pdept Ojena",
058: "S1 Pdept Oapp", "S1 Pmgr US4", "S1 Ptitle Oboss",
059:
060: "S2 Pname Obb", "S2 Psex Omale", "S2 Pdept Ogenesis",
061: "S2 Pdept Oapp", "S2 Pmgr US4", "S2 Ptitle Oboss",
062:
063: "S3 Pname Ojb", "S3 Psex Ofemale", "S3 Pdept Oapp",
064: "S3 Pmgr US1", "S3 Ptitle Oboss",
065:
066: "S4 Pname Odick", "S4 Psex Omale", "S4 Pmgr Oshane",
067: "S4 Ptitle Obigboss",
068:
069: "S5 Pname Okers", "S5 Psex Omale", "S5 Pdept Ojena",
070: "S5 Pdept Ordql", "S5 Pmgr US1", "S5 Ptitle Ogrunt",
071:
072: "S6 Pname Ojjc", "S6 Psex Omale", "S6 Pdept Ojena",
073: "S6 Pdept Ordf", "S6 Pdept Oowl", "S6 Pmgr US1",
074: "S6 Ptitle Ogrunt",
075:
076: "S7 Pname Oder", "S7 Psex Omale", "S7 Pdept Ojena",
077: "S7 Pdept Ordf", "S7 Pdept Oowl", "S7 Pmgr US1",
078: "S7 Ptitle Ogrunt", "S7 Ptitle Oboss",
079:
080: "S8 Pname Obmk", "S8 Psex Omale", "S8 Pdept Ojena",
081: "S8 Pdept Ordf", "S8 Pmgr US1", "S8 Ptitle Ogrunt",
082: "S8 Ptitle Oboss",
083:
084: "S9 Pname Oas", "S9 Psex Omale", "S9 Pdept Ojena",
085: "S9 Pdept Ordf", "S9 Pdept Ordql", "S9 Pmgr US1",
086: "S9 Ptitle Ogrunt",
087:
088: "S10 Pname Oian", "S10 Psex Omale", "S10 Pdept Ojena",
089: "S10 Pdept Oowl", "S10 Pmgr US1", "S10 Ptitle Ogrunt",
090:
091: "S11 Pname Osteveb", "S11 Psex Omale", "S11 Pdept Oapp",
092: "S11 Pmgr US3", "S11 Ptitle Ogrunt",
093:
094: "S12 Pname Ostevec", "S12 Psex Omale", "S12 Pdept Oapp",
095: "S12 Pmgr US3", "S12 Ptitle Ogrunt",
096:
097: "S13 Pname Ocs", "S13 Psex Omale", "S13 Pdept Ojena",
098: "S13 Pdept Ogenesis", "S13 Pmgr US2",
099: "S13 Ptitle Ogrunt",
100:
101: "S14 Pname Ohk", "S14 Psex Ofemale", "S14 Pdept Oapp",
102: "S14 Pdept Ogenesis", "S14 Pmgr US2",
103: "S14 Ptitle Ogrunt",
104:
105: "S15 Pname Oks",
106: "S15 Psex Omale",
107: "S15 Pdept Oapp",
108: "S15 Pdept Ogenesis",
109: "S15 Pmgr US2",
110:
111: "S16 Pname Owkw",
112: "S16 Psex Omale",
113: "S16 Pdept Ojena",
114: "S16 Pdept Oapp",
115: "S16 Pmgr US2",
116: "S16 Ptitle Ogrunt",
117:
118: // reify the first few sets of statements
119:
120: "N1 S1 Pname Omm", "N2 S1 Psex Omale",
121: "N3 S1 Pdept Ojena", "N4 S1 Pdept Oapp",
122: "N5 S1 Pmgr US4", "N6 S1 Ptitle Oboss",
123:
124: "N7 S2 Pname Obb", "N8 S2 Psex Omale",
125: "N9 S2 Pdept Ogenesis", "N10 S2 Pdept Oapp",
126: "N11 S2 Pmgr US4", "N12 S2 Ptitle Oboss",
127:
128: "N13 S3 Pname Ojb", "N14 S3 Psex Ofemale",
129: "N15 S3 Pdept Oapp", "N16 S3 Pmgr US1",
130: "N17 S3 Ptitle Oboss",
131:
132: "N18 S4 Pname Odick", "N19 S4 Psex Omale",
133: "N20 S4 Pmgr Oshane", "N21 S4 Ptitle Obigboss",
134:
135: "N22 S5 Pname Okers", "N23 S5 Psex Omale",
136: "N24 S5 Pdept Ojena", "N25 S5 Pdept Ordql",
137: "N26 S5 Pmgr US1", "N27 S5 Ptitle Ogrunt",
138:
139: };
140:
141: public void setUp() throws Exception {
142: super .setUp();
143: }
144:
145: protected Graph standard() {
146: return fetchGraph(ReificationStyle.Standard);
147: }
148:
149: protected Graph convenient() {
150: return fetchGraph(ReificationStyle.Convenient);
151: }
152:
153: protected Graph fetchGraph(ReificationStyle style) {
154: Graph s = getGraph(style);
155: loadGraph(s);
156: return s;
157: }
158:
159: protected void tearDown() throws Exception {
160: super .tearDown();
161: }
162:
163: /**
164: The lots-of-dots prefix to use to make things long
165: */
166: protected final String longPrefix = makeLongPrefix();
167:
168: /**
169: Answer a string of 256 dots.
170: */
171: private String makeLongPrefix() {
172: StringBuffer sb = new StringBuffer(256);
173: for (int i = 0; i < 256; i += 1)
174: sb.append('.');
175: return sb.toString();
176: }
177:
178: protected Node makeResource(String u) {
179: return Node.createURI(expandLong(u));
180: }
181:
182: protected Node makeObject(String u) {
183: boolean isRef = u.charAt(0) == 'U';
184: return isRef ? makeResource(u.substring(1)) : Node
185: .createLiteral(new LiteralLabel(expandLong(u)));
186: }
187:
188: protected String expandLong(String s) {
189: return s.charAt(0) == 'L' ? longPrefix + s.substring(1) : s;
190: }
191:
192: static int stmtCnt = 0;
193:
194: protected void loadGraph(Graph g) {
195: Reifier r = g.getReifier();
196: for (int i = 0; i < statementList.length; i++) {
197: StringTokenizer st = new StringTokenizer(statementList[i]);
198: String k = st.nextToken();
199: if (k.charAt(0) == 'N')
200: r.reifyAs(makeResource(k), nextTriple(st.nextToken(),
201: st));
202: else
203: g.add(nextTriple(k, st));
204: stmtCnt++;
205: }
206: }
207:
208: protected Triple nextTriple(String k, StringTokenizer st) {
209: Node s = makeResource(k);
210: Node p = makeResource(st.nextToken());
211: Node o = makeObject(st.nextToken());
212: return Triple.create(s, p, o);
213: }
214:
215: final Node V1 = node("?v1");
216: final Node V2 = node("?v2");
217: final Node V3 = node("?v3");
218: final Node V4 = node("?v4");
219: final Node V5 = node("?v5");
220:
221: final Node Ptitle = makeResource("Ptitle");
222: final Node Psex = makeResource("Psex");
223: final Node Pname = makeResource("Pname");
224: final Node Pmgr = makeResource("Pmgr");
225: final Node Pcard = makeResource("Pcard");
226: final Node Pcardmax = makeResource("Pcardmax");
227: final Node Prange = makeResource("Prange");
228: final Node Pdept = makeResource("Pdept");
229: final Node S1 = makeResource("S1");
230:
231: // object constants
232: final Node Ogrunt = makeObject("Ogrunt");
233: final Node Ofemale = makeObject("Ofemale");
234: final Node Omale = makeObject("Omale");
235: final Node Obigboss = makeObject("Obigboss");
236: final Node Oboss = makeObject("Oboss");
237: final Node Oshane = makeObject("Oshane");
238: final Node Oliteral = makeObject("Oliteral");
239: final Node Oresource = makeObject("Oresource");
240: final Node Oapp = makeObject("Oapp");
241: final Node Ogenesis = makeObject("Ogenesis");
242:
243: final Node O1 = makeObject("O1");
244:
245: public void test0() {
246: Query query = new Query();
247: query.addMatch(V1, Ptitle, Ogrunt);
248: query.addMatch(V1, Psex, Ofemale);
249: query.addMatch(V1, Pname, V3);
250: checkCount(1, standard(), query, new Node[] { V1, V3 });
251: }
252:
253: /**
254: Q1: get names of managers of female grunts; this has a joining variable.
255: */
256: public void test1() {
257: Query query = new Query();
258: query.addMatch(V1, Ptitle, Ogrunt);
259: query.addMatch(V1, Psex, Ofemale);
260: query.addMatch(V1, Pmgr, V2);
261: query.addMatch(V2, Pname, V3);
262: checkCount(1, standard(), query, new Node[] { V1, V3 });
263: }
264:
265: /**
266: Q2: get names of female grunts with female managers
267: */
268: public void test2() {
269: Query query = new Query();
270: query.addMatch(V1, Ptitle, Ogrunt);
271: query.addMatch(V1, Psex, Ofemale);
272: query.addMatch(V1, Pmgr, V2);
273: query.addMatch(V2, Psex, Ofemale);
274: query.addMatch(V1, Pname, V3);
275: checkCount(0, standard(), query, new Node[] { V1, V3 });
276: }
277:
278: /**
279: Q3.0: get all properties of the bigboss
280: */
281: public void test3a() {
282: Query query = new Query();
283: query.addMatch(V1, Ptitle, Obigboss);
284: query.addMatch(V1, Pmgr, Oshane);
285: query.addMatch(V1, V2, V3);
286: checkCount(4, standard(), query, new Node[] { V1, V2, V3 });
287: }
288:
289: /**
290: Q3: get all properties of female grunts with male managers
291: this has a predicate variable. for standard reification, it
292: requires a multi-stage query. for convenient, minimal, it can
293: be done as a single stage (since reification is not queried).
294: */
295: public void test3b() {
296: Query query = new Query();
297: query.addMatch(V1, Ptitle, Ogrunt);
298: query.addMatch(V1, Psex, Ofemale);
299: query.addMatch(V1, Pmgr, V2);
300: query.addMatch(V2, Psex, Omale);
301: query.addMatch(V1, V3, V4);
302: checkCount(6, standard(), query, new Node[] { V1, V3, V4 });
303: }
304:
305: /**
306: Q4: get all single-valued, required, literal properties of the bigboss
307: similar to Q3 in terms of stages.
308: */
309: public void test4() {
310: Query query = new Query();
311: query.addMatch(V1, Ptitle, Obigboss);
312: query.addMatch(V1, Pmgr, Oshane);
313: query.addMatch(V2, Pcard, O1);
314: query.addMatch(V2, Prange, Oliteral);
315: query.addMatch(V1, V2, V3);
316: checkCount(2, standard(), query, new Node[] { V2, V3 });
317: }
318:
319: /**
320: Q5: list the name and gender of martin's boss, where the pmgr property
321: is determined by a query).
322: similar to Q3 in terms of stages.
323: */
324: public void test5() {
325: Query query = new Query();
326: query.addMatch(V1, Pcardmax, O1); // get the mgr property
327: query.addMatch(V1, Prange, Oresource);
328: query.addMatch(S1, V1, V2); // get mm's mgr
329: query.addMatch(V2, Pname, V3);
330: query.addMatch(V2, Psex, V4);
331: checkCount(1, standard(), query, new Node[] { V2, V3, V4 });
332: }
333:
334: /**
335: Q6: list the reified subjects, predicates and objects.
336: should return nothing for minimal, convenient reification.
337: */
338: public void test6() {
339: Query query = new Query();
340: query.addMatch(V1, RDF.Nodes.subject, V2);
341: query.addMatch(V1, RDF.Nodes.predicate, V3);
342: query.addMatch(V1, RDF.Nodes.object, V4);
343: /* */
344: checkCount(27, standard(), query, new Node[] { V2, V3, V4 });
345: checkCount(0, convenient(), query, new Node[] { V2, V3, V4 });
346: }
347:
348: /**
349: Q7: list the reified predicates about the bigboss.
350: should return nothing for minimal, convenient reification.
351: */
352: public void test7() {
353: Query query = new Query();
354: query.addMatch(V1, RDF.Nodes.subject, V2);
355: query.addMatch(V1, RDF.Nodes.predicate, Ptitle);
356: query.addMatch(V1, RDF.Nodes.object, Obigboss);
357: query.addMatch(V3, RDF.Nodes.subject, V2);
358: query.addMatch(V3, RDF.Nodes.predicate, V4);
359: /* */
360: checkCount(4, standard(), query, new Node[] { V2, V3 });
361: }
362:
363: /**
364: Q8: list the reification quads for the bigboss.
365: should return nothing for minimal, convenient reification.
366: */
367: public void test8() {
368: Query query = new Query();
369: query.addMatch(V1, RDF.Nodes.subject, V2);
370: query.addMatch(V1, RDF.Nodes.predicate, Ptitle);
371: query.addMatch(V1, RDF.Nodes.object, Obigboss);
372: query.addMatch(V3, RDF.Nodes.subject, V2);
373: query.addMatch(V3, V4, V5); // V4 and V5 serve duty as ANY
374: checkCount(16, standard(), query, new Node[] { V3 });
375: }
376:
377: /**
378: Check that the number of results obtained from the query over the graph is
379: that expected.
380:
381: @param expected the number of results expected from the query
382: @param g the graph to run the query over
383: @param q the query to apply to the graph
384: @param results the results-variable array
385: */
386: private void checkCount(int expected, Graph g, Query q,
387: Node[] results) {
388: BindingQueryPlan plan = g.queryHandler().prepareBindings(q,
389: results);
390: ExtendedIterator it = plan.executeBindings();
391: assertEquals("number of reified statements", expected,
392: queryResultCount(it));
393: it.close();
394: }
395:
396: /**
397: Answer the number of elements in the iterator; each such element should be
398: a List (and we make sure size() works on it, don't know why).
399:
400: @param it the iterator to run down
401: @return the number of elements in that iterator
402: */
403: protected int queryResultCount(ExtendedIterator it) {
404: int n = 0;
405: while (it.hasNext()) {
406: n++;
407: ((List) it.next()).size(); // hedgehog asks, do we need to check this works?
408: }
409: return n;
410: }
411:
412: }
413:
414: /*
415: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
416: All rights reserved.
417:
418: Redistribution and use in source and binary forms, with or without
419: modification, are permitted provided that the following conditions
420: are met:
421:
422: 1. Redistributions of source code must retain the above copyright
423: notice, this list of conditions and the following disclaimer.
424:
425: 2. Redistributions in binary form must reproduce the above copyright
426: notice, this list of conditions and the following disclaimer in the
427: documentation and/or other materials provided with the distribution.
428:
429: 3. The name of the author may not be used to endorse or promote products
430: derived from this software without specific prior written permission.
431:
432: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
433: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
434: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
435: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
436: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
437: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
438: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
439: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
440: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
441: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
442: */
|