1 6 7 package com.hp.hpl.jena.graph.query.test; 8 9 import com.hp.hpl.jena.graph.*; 10 import com.hp.hpl.jena.graph.query.*; 11 import com.hp.hpl.jena.shared.JenaException; 12 import com.hp.hpl.jena.shared.QueryStageException; 13 import com.hp.hpl.jena.util.CollectionFactory; 14 import com.hp.hpl.jena.util.iterator.*; 15 import com.hp.hpl.jena.graph.impl.*; 16 17 import java.util.*; 18 import junit.framework.*; 19 20 24 public abstract class AbstractTestQuery extends QueryTestBase 25 { 26 public AbstractTestQuery(String name) 27 { super(name); } 28 29 public abstract Graph getGraph(); 30 31 protected Query Q; 32 protected Node O = node( "?O" ); 33 protected Graph empty; 34 protected Graph single; 35 36 protected final Node [] none = new Node[] {}; 37 38 protected final Node [] justX = new Node [] {Query.X}; 39 40 public static TestSuite suite() 41 { return new TestSuite( QueryTest.class ); } 42 43 public Graph getGraphWith( String facts ) 44 { return graphAdd( getGraph(), facts ); } 45 46 public void setUp() 47 { 48 Q = new Query(); 49 empty = getGraphWith( "" ); 50 single = getGraphWith( "spindizzies drive cities" ); 51 } 52 53 private void testTreeQuery( String title, String content, String pattern, String correct ) 54 { 55 Graph gc = getGraphWith( content ), gp = getGraphWith( pattern ); 56 Graph answer = gc.queryHandler().prepareTree( gp ).executeTree(); 57 if (title.equals( "" )) title = "checking {" + content + "} against {" + pattern + "} should give {" + correct + "}" + " not " + answer; 58 assertIsomorphic( title, getGraphWith( correct ), answer ); 59 } 60 61 private void testTreeQuery( String content, String pattern, String answer ) 62 { 63 testTreeQuery( "checking", content, pattern, answer ); 64 } 65 66 private static final String [][] tests = 67 { 68 { "", "pigs might fly", "", "" }, 69 { "", "", "pigs might fly", "" }, 70 { "", "a pings b; b pings c", "a pings _x; _x pings c", "a pings b; b pings c" }, 71 { "", "a pings b; b pings c; a pings x; x pings c", "a pings _x; _x pings c", "a pings b; b pings c; a pings x; x pings c" } 72 }; 73 74 public void testManyThings() 75 { 76 for (int i = 0; i < tests.length; i += 1) 77 testTreeQuery( tests[i][0], tests[i][1], tests[i][2], tests[i][3] ); 78 } 79 80 public void testAtomicTreeQuery() 81 { 82 testTreeQuery( "pigs might fly; birds will joke; cats must watch", "birds will joke", "birds will joke" ); 83 } 84 85 public void testCompositeTreeQuery() 86 { 87 testTreeQuery 88 ( "pigs might fly; birds will joke; cats must watch", "birds will joke; pigs might fly", "pigs might fly; birds will joke" ); 89 } 90 91 public void testChainedTreeQuery() 92 { 93 testTreeQuery( "a pings b; b pings c; c pings d", "a pings b; b pings c", "a pings b; b pings c" ); 94 } 95 96 public void testEmptyIterator() 97 { 98 Graph empty = getGraph(); 99 Query q = new Query().addMatch( X, Y, Z ); 100 BindingQueryPlan bqp = empty.queryHandler().prepareBindings( q, justX ); 101 try 102 { 103 bqp.executeBindings().next(); 104 fail( "there are no bindings; next() should fail" ); 105 } 106 catch (NoSuchElementException e) 107 { pass(); } 108 } 109 110 public void testBinding1( ) 111 { 112 Graph single = getGraphWith( "rice grows quickly" ); 113 Query q = new Query(); 114 Node V1 = node( "?v1" ), V3 = node( "?v3" ); 115 BindingQueryPlan qp = single.queryHandler().prepareBindings( q.addMatch( V1, node("grows"), V3 ), new Node[] {V1, V3} ); 116 Domain binding = (Domain) qp.executeBindings().next(); 117 assertEquals( "binding subject to rice", binding.get(0), node("rice") ); 118 assertEquals( "binding object to quickly", binding.get(1), node("quickly") ); 119 } 120 121 public void testBinding2() { 122 Graph several = getGraphWith("rice grows quickly; time isan illusion"); 123 String [][] answers = { { "time", "isan", "illusion" }, { 124 "rice", "grows", "quickly" } 125 }; 126 boolean[] found = { false, false }; 127 Query q = new Query(); 128 Node V1 = node("?v1"), V2 = node("?v2"), V3 = node("?v3"); 129 BindingQueryPlan qp = 130 several.queryHandler().prepareBindings( 131 q.addMatch(V1, V2, V3), 132 new Node[] { V1, V2, V3 }); 133 Iterator bindings = qp.executeBindings(); 134 for (int i = 0; i < answers.length; i += 1) { 135 if (bindings.hasNext() == false) 136 fail("wanted some more results"); 137 Domain bound = (Domain) bindings.next(); 138 for (int k = 0; k < answers.length; k++) { 139 if (found[k]) 140 continue; 141 boolean match = true; 142 for (int j = 0; j < 3; j += 1) { 143 if (!bound.get(j).equals(node(answers[k][j]))) { 144 match = false; 145 break; 146 } 147 } 148 if (match) { 149 found[k] = true; 150 break; 151 } 152 } 153 } 154 for (int k = 0; k < answers.length; k++) { 155 if (!found[k]) 156 assertTrue("binding failure", false); 157 } 158 assertFalse("iterator should be empty", bindings.hasNext()); 159 } 160 161 162 public void testMultiplePatterns() 163 { 164 Graph bookish = getGraphWith( "ben wrote Clayface; Starfish ingenre SF; Clayface ingenre Geology; bill wrote Starfish" ); 165 Query q = new Query(); 166 Node A = node( "?A" ); 167 q.addMatch( X, node("wrote"), A ).addMatch( A, node("ingenre"), node("SF") ); 168 BindingQueryPlan qp = bookish.queryHandler().prepareBindings( q, justX ); 169 Iterator bindings = qp.executeBindings(); 170 if (bindings.hasNext()) 171 { 172 Domain it = (Domain) bindings.next(); 173 if (it.size() > 0) 174 { 175 if (it.get(0).equals( node("bill") )) 176 { 177 if (bindings.hasNext()) 178 System.out.println( "! failed: more than one multiple pattern answer: " + bindings.next() ); 179 } 180 else 181 System.out.println( "! failed: multiple pattern answer should be 'bill'" ); 182 } 183 else 184 System.out.println( "! failed: multiple pattern answer should have one element" ); 185 } 186 else 187 System.out.println( "! failed: multiple pattern query should have an answer" ); 188 } 189 190 194 protected ExtendedIterator eb( Graph g, Query q, Node [] nodes ) 195 { return g.queryHandler().prepareBindings( q, nodes ).executeBindings(); } 196 197 protected List ebList( Graph g, Query q, Node [] nodes ) 198 { return iteratorToList( eb( g, q, nodes ) ); } 199 200 protected Set ebSet( Graph g, Query q, Node [] nodes ) 201 { return iteratorToSet( eb( g, q, nodes ) ); } 202 203 public void testNodeVariablesA() 204 { 205 Graph mine = getGraphWith( "storms hit England" ); 206 Node spoo = node( "?spoo" ); 207 Q.addMatch( spoo, node("hit"), node("England") ); 208 ClosableIterator it = eb( mine, Q, new Node[] {spoo} ); 209 assertTrue( "tnv: it has a solution", it.hasNext() ); 210 assertEquals( "", node("storms"), ((List) it.next()).get(0) ); 211 assertFalse( "tnv: just the one solution", it.hasNext() ); 212 } 213 214 public void testNodeVariablesB() 215 { 216 Graph mine = getGraphWith( "storms hit England" ); 217 Node spoo = node( "?spoo" ), flarn = node( "?flarn" ); 218 Q.addMatch( spoo, node("hit"), flarn ); 219 ClosableIterator it = eb( mine, Q, new Node[] {flarn, spoo} ); 220 assertTrue( "tnv: it has a solution", it.hasNext() ); 221 List answer = (List) it.next(); 222 assertEquals( "tnvB", node("storms"), answer.get(1) ); 223 assertEquals( "tnvB", node("England"), answer.get(0) ); 224 assertFalse( "tnv: just the one solution", it.hasNext() ); 225 } 226 227 public void testBindingQuery() 228 { 229 Graph empty = getGraphWith( "" ); 230 Graph base = getGraphWith( "pigs might fly; cats chase mice; dogs chase cars; cats might purr" ); 231 232 Query any = new Query().addMatch( Query.ANY, Query.ANY, Query.ANY ); 233 assertFalse( "empty graph, no bindings", eb( empty, any, none ).hasNext() ); 234 assertTrue( "full graph, > 0 bindings", eb( base, new Query(), none ).hasNext() ); 235 } 236 237 public void testEmpty() 238 { 239 List bindings = ebList( empty, Q, none ); 240 assertEquals( "testEmpty: select [] from {} => 1 empty binding [size]", bindings.size(), 1 ); 241 Domain d = (Domain) bindings.get( 0 ); 242 assertEquals( "testEmpty: select [] from {} => 1 empty binding [width]", d.size(), 0 ); 243 } 244 245 public void testOneMatch() 246 { 247 Q.addMatch( X, Query.ANY, Query.ANY ); 248 List bindings = ebList( single, Q, justX ); 249 assertEquals( "select X from {spindizzies drive cities} => 1 binding [size]", bindings.size(), 1 ); 250 Domain d = (Domain) bindings.get( 0 ); 251 assertEquals( "select X from {spindizzies drive cities} => 1 binding [width]", d.size(), 1 ); 252 assertTrue( "select X from {spindizzies drive cities} => 1 binding [value]", d.get( 0 ).equals( node( "spindizzies" ) ) ); 253 } 254 255 public void testMismatch() 256 { 257 Q.addMatch( X, X, X ); 258 List bindings = ebList( single, Q, justX ); 259 assertEquals( "bindings mismatch (X X X)", bindings.size(), 0 ); 260 } 261 262 public void testXXXMatch1() 263 { 264 Q.addMatch( X, X, X ); 265 Graph xxx = getGraphWith( "ring ring ring" ); 266 List bindings = ebList( xxx, Q, justX ); 267 assertEquals( "bindings match (X X X)", bindings.size(), 1 ); 268 } 269 270 public void testXXXMatch3() 271 { 272 Q.addMatch( X, X, X ); 273 Graph xxx = getGraphWith( "ring ring ring; ding ding ding; ping ping ping" ); 274 List bindings = ebList( xxx, Q, justX ); 275 assertEquals( "bindings match (X X X)", bindings.size(), 3 ); 276 277 Set found = CollectionFactory.createHashedSet(); 278 for (int i = 0; i < bindings.size(); i += 1) 279 { 280 Domain d = (Domain) bindings.get( i ); 281 assertEquals( "one bound variable", d.size(), 1 ); 282 found.add( d.get( 0 ) ); 283 } 284 Set wanted = nodeSet( "ring ding ping" ); 285 assertEquals( "testMatch getting {ring ding ping}", found, wanted ); 286 } 287 288 public void testTwoPatterns() 289 { 290 Node reads = node("reads"), inGenre = node("inGenre"); 291 Graph g = getGraphWith( "chris reads blish; blish inGenre SF" ); 292 Q.addMatch( X, reads, Y ); 294 Q.addMatch( Y, inGenre, Z ); 295 List bindings = ebList( g, Q, new Node [] {X, Z} ); 296 assertTrue( "testTwoPatterns: one binding", bindings.size() == 1 ); 297 Domain d = (Domain) bindings.get( 0 ); 298 assertTrue( "testTwoPatterns: width 2", d.size() >= 2 ); 300 assertEquals( "testTwoPatterns: X = chris", d.get(0), node("chris") ); 301 assertEquals( "testTwoPatterns: Y = SF", d.get(1), node("SF") ); 302 } 303 304 public void testGraphQuery() 305 { 306 Graph pattern = getGraphWith( "?X reads ?Y; ?Y inGenre ?Z" ); 307 Graph target = getGraphWith( "chris reads blish; blish inGenre SF" ); 308 Query q = new Query( pattern ); 310 List bindings = ebList( target, q, new Node [] {node("?X"), node("?Z")} ); 311 assertEquals( "testTwoPatterns: one binding", 1, bindings.size() ); 312 Domain d = (Domain) bindings.get( 0 ); 313 assertTrue( "testTwoPatterns: width 2", d.size() >= 2 ); 315 assertEquals( "testTwoPatterns: X = chris", d.get(0), node("chris") ); 316 assertEquals( "testTwoPatterns: Y = SF", d.get(1), node("SF") ); 317 } 318 319 public void testTwoGraphs() 320 { 321 Graph a = getGraphWith( "chris reads blish; chris reads norton; chris eats curry" ); 322 Graph b = getGraphWith( "blish inGenre SF; curry inGenre food" ); 323 Node reads = node("reads"), inGenre = node("inGenre"); 324 Q.addMatch( "a", X, reads, Y ).addMatch( "b", Y, inGenre, Z ); 325 NamedGraphMap args = Q.args().put( "a", a ).put( "b", b ); 326 List bindings = iteratorToList( Q.executeBindings( args, new Node [] {X, Z} ) ); assertEquals( "testTwoGraphs: one binding", bindings.size(), 1 ); 328 Domain d = (Domain) bindings.get( 0 ); 329 assertTrue( "testTwoGraphs: width 2", d.size() >= 2 ); 330 assertEquals( "testTwoGraphs: X = chris", d.get(0), node("chris") ); 331 assertEquals( "testTwoGraphs: Y = SF", d.get(1), node("SF") ); 332 } 333 334 public void testGraphConstraints( String title, Expression constraint, String wanted ) 335 { 336 Query Q = new Query() 337 .addMatch( Query.ANY, Query.ANY, O ) 338 .addConstraint( constraint ); 339 Graph G = getGraphWith( "pigs fly south; dogs fly badly; plans fly flat" ); 340 Set results = iteratorToSet( eb( G, Q, new Node[] {O} ).mapWith( getFirst ) ); 341 assertEquals( "tgs", nodeSet( wanted ), results ); 342 } 343 344 public void testGraphConstraints() 345 { 346 Node badly = node( "badly" ), flat = node( "flat" ); 347 testGraphConstraints( "tgs A", Expression.TRUE, "south flat badly" ); 348 testGraphConstraints( "tgs B", notEqual( O, badly ), "south flat" ); 349 testGraphConstraints( "tgs C", Dyadic.and( notEqual( O, badly ), notEqual( O, flat ) ), "south" ); 350 } 351 352 private void helpConstraint( String title, Expression constraints, int n ) 353 { 354 Query q = new Query(); 355 Graph g = getGraphWith( "blish wrote CIF; blish wrote VOR; hambly wrote Darwath; feynman mechanicked quanta" ); 356 q.addMatch( X, node("wrote"), Query.ANY ); 357 q.addConstraint( constraints ); 358 List bindings = ebList( g, q, justX ); 359 assertEquals( "testConstraint " + title + ": number of bindings", n, bindings.size() ); 360 } 361 362 public void testConstraint() 363 { 364 helpConstraint( "none", Expression.TRUE, 3 ); 365 helpConstraint( "X /= blish", notEqual( X, node( "blish" ) ), 1 ); 366 helpConstraint( "X /= blish & X /= hambly", Dyadic.and( notEqual( X, node( "blish" ) ), notEqual( X, node( "hambly" ) ) ), 0 ); 367 } 368 369 private void helpConstraintThree( String title, Expression c, int n ) 370 { 371 Query q = new Query(); 372 Graph g = getGraphWith( "brust wrote jhereg; hedgehog hacked code; angel age 230; brust wrote 230" ); 373 q.addConstraint( c ); 374 q.addMatch( X, Y, Z ); 375 List bindings = ebList( g, q, new Node [] {X, Z} ); 376 assertEquals( "testConstraint " + title + ": number of bindings", n, bindings.size() ); 377 } 378 379 public void testConstraintThree() 380 { 381 helpConstraintThree( "testConstraintThree 1:", areEqual( X, node( "brust" ) ), 2 ); 382 helpConstraintThree( "testConstraintThree 2:", areEqual( Y, node( "hacked" ) ), 1 ); 383 helpConstraintThree( "testConstraintThree 3:", areEqual( Z, node( "230" ) ), 2 ); 384 } 385 386 public void testConstraintFour() 387 { 388 Query q = new Query(); 389 Graph g = getGraphWith( "bill pinged ben; ben pinged weed; weed pinged weed; bill ignored bill" ); 390 q.addMatch( X, node("pinged"), Y ); 391 q.addConstraint( notEqual( X, Y ) ); 392 Set bindings = iteratorToSet( eb( g, q, justX ).mapWith(getFirst) ); 393 assertEquals( arrayToSet( new Node[] {node("bill"), node("ben")} ), bindings ); 394 } 395 396 399 public void testMatchConstraint() 400 { 401 Set expected = CollectionFactory.createHashedSet(); 402 expected.add( node( "beta" ) ); 403 Query q = new Query() 404 .addMatch( X, node( "ppp" ), Y ).addConstraint( matches( Y, node( "'ell'" ) ) ) 405 ; 406 Graph g = getGraphWith( "alpha ppp beta; beta ppp 'hello'; gamma ppp 'goodbye'" ); 407 Set bindings = iteratorToSet( eb( g, q, justX ).mapWith( getFirst ) ); 408 assertEquals( expected, bindings ); 409 } 410 411 414 public void testExtractConstraint() 415 { 416 } 418 419 public void testStringResults() 420 { 421 Graph g = getGraphWith( "ding dong dilly" ); 422 Query q = new Query() .addMatch( X, Y, Query.ANY ); 423 List bindings = ebList( g, q, new Node [] {X, Y} ); 424 assertEquals( "one result back by name", bindings.size(), 1 ); 425 assertEquals( "x = ding", ((Domain) bindings.get(0)).get(0), node("ding") ); 426 } 427 428 435 public void testMissingVariable() 436 { 437 Graph g = getGraphWith( "x y z" ); 438 List bindings = ebList( g, Q, new Node [] {X, Y} ); 439 List L = (List) bindings.get(0); 440 assertEquals( "undefined variables get null", null, L.get( 0 ) ); 441 } 442 443 446 public void testDisconnected() 447 { 448 Graph g = getGraphWith( "x pred1 foo; y pred2 bar" ); 449 Query q = new Query( getGraphWith( "?X ?? foo; ?Y ?? bar" ) ); 450 List bindings = ebList( g, q, nodes( "?X ?Y" ) ); 451 assertEquals( 1, bindings.size() ); 452 assertEquals( node( "x" ), ((Domain) bindings.get(0)).get(0) ); 453 assertEquals( node( "y" ), ((Domain) bindings.get(0)).get(1) ); 454 } 455 456 459 public void testQueryTripleOrder() 460 { 461 Triple t1 = Triple.create( "A B C" ), t2 = Triple.create( "D E F" ); 462 List desired = Arrays.asList( new Triple[] {t1, t2} ); 463 List obtained = getTriplesFromQuery( desired ); 464 assertEquals( desired, obtained ); 465 } 466 467 473 private List getTriplesFromQuery( List desired ) 474 { 475 Query q = new Query(); 476 final Triple [][] tripleses = new Triple[1][]; 477 final Graph g = new GraphBase() 478 { 479 public ExtendedIterator graphBaseFind( TripleMatch tm ) 480 { return NullIterator.instance; } 481 public QueryHandler queryHandler() 482 { 483 return new SimpleQueryHandler( this ) 484 { 485 public Stage patternStage( Mapping map, ExpressionSet constraints, Triple [] t ) 486 { 487 if (t.length > 1) tripleses[0] = t; 488 return super.patternStage( map, constraints, t ); 489 } 490 } 491 ; 492 } 493 }; 494 for (int i = 0; i < desired.size(); i += 1) q.addMatch( (Triple) desired.get(i) ); 495 eb( g, q, none ); 496 return Arrays.asList( tripleses[0] ); 497 } 498 499 502 public void testVariableCount() 503 { 504 assertCount( 0, "" ); 505 assertCount( 0, "x R y" ); 506 assertCount( 1, "?x R y" ); 507 assertCount( 1, "?x R y", "?x" ); 508 assertCount( 2, "?x R y", "?z" ); 509 assertCount( 1, "?x R ?x" ); 510 assertCount( 2, "?x R ?y" ); 511 assertCount( 3, "?x R ?y", "?z" ); 512 assertCount( 3, "?x ?R ?y" ); 513 assertCount( 6, "?x ?R ?y; ?a ?S ?c" ); 514 assertCount( 6, "?x ?R ?y; ?a ?S ?c", "?x" ); 515 assertCount( 6, "?x ?R ?y; ?a ?S ?c", "?x ?c" ); 516 assertCount( 6, "?x ?R ?y; ?a ?S ?c", "?x ?y ?c" ); 517 assertCount( 7, "?x ?R ?y; ?a ?S ?c", "?dog" ); 518 assertCount( 8, "?x ?R ?y; ?a ?S ?c", "?dog ?cat ?x" ); 519 assertCount( 18, "?a ?b ?c; ?d ?e ?f; ?g ?h ?i; ?j ?k ?l; ?m ?n ?o; ?p ?q ?r" ); 520 } 521 522 public void assertCount( int expected, String query ) 523 { assertCount( expected, query, "" ); } 524 525 public void assertCount( int expected, String query, String vars ) 526 { 527 Graph g = getGraphWith( "" ); 528 Query q = new Query(); 529 Triple [] triples = tripleArray( query ); 530 for (int i = 0; i < triples.length; i += 1) q.addMatch( triples[i] ); 531 q.executeBindings( g, nodes( vars ) ); 533 assertEquals( expected, q.getVariableCount() ); 534 } 535 536 539 public void testQueryConstraintUnbound() 540 { 541 Query q = new Query() 542 .addConstraint( notEqual( X, Z ) ) 543 .addMatch( X, Query.ANY, X ) 544 ; 545 Graph g = getGraphWith( "x R x; x R y" ); 546 try 547 { 548 ExtendedIterator it = eb( g, q, justX ); 549 fail( "should spot unbound variable" ); 550 } 551 catch (Query.UnboundVariableException b) { pass(); } 552 } 553 554 public void testCloseQuery() 555 { 556 Graph g = getGraphWith( "x R y; a P b; i L j; d X f; h S g; no more heroes" ); 557 for (int n = 0; n < 1000; n += 1) graphAdd( g, "ping pong X" + n ); 558 Query q = new Query().addMatch( Query.S, Query.P, Query.O ); 559 List stages = new ArrayList(); 560 ExtendedIterator it = eb( g, q, nodes( "?P" ) ); 561 it.next(); 562 for (int i = 0; i < stages.size(); i += 1) assertFalse( ((Stage) stages.get(i)).isClosed() ); 563 it.close(); 564 for (int i = 0; i < stages.size(); i += 1) assertTrue( ((Stage) stages.get(i)).isClosed() ); 565 } 566 567 public void testRewriteStartswithExpression() 568 { 569 Query q = new Query(); 570 Expression L = constant( "x" ); 571 Expression R = createSimplePattern( "^begins" ); 572 Expression provided = dyadic( L, "Q_StringMatch", R ); 573 Expression desired = dyadic( L, "J_startsWith", constant( "begins" ) ); 574 q.addConstraint( provided ); 575 Expression e2 = (Expression) q.getConstraints().iterator().next(); 576 assertEquals( desired, e2 ); 577 } 578 579 public void testRewriteStartswithInsensitiveExpression() 580 { 581 Query q = new Query(); 582 Expression L = constant( "x" ); 583 Expression R = createModifiedPattern( "^begins", "i" ); 584 Expression provided = dyadic( L, "Q_StringMatch", R ); 585 Expression desired = dyadic( L, "J_startsWithInsensitive", constant( "begins" ) ); 586 q.addConstraint( provided ); 587 Expression e2 = (Expression) q.getConstraints().iterator().next(); 588 assertEquals( desired, e2 ); 589 } 590 591 public void testRewriteEndswithExpression() 592 { 593 Query q = new Query(); 594 Expression L = constant( "x" ); 595 Expression R = createSimplePattern( "ends$" ); 596 Expression provided = dyadic( L, "Q_StringMatch", R ); 597 Expression desired = dyadic( L, "J_endsWith", constant( "ends" ) ); 598 q.addConstraint( provided ); 599 Expression e2 = (Expression) q.getConstraints().iterator().next(); 600 assertEquals( desired, e2 ); 601 } 602 603 public void testRewriteEndswithInsensitiveExpression() 604 { 605 Query q = new Query(); 606 Expression L = constant( "x" ); 607 Expression R = createModifiedPattern( "ends$", "i" ); 608 Expression provided = dyadic( L, "Q_StringMatch", R ); 609 Expression desired = dyadic( L, "J_endsWithInsensitive", constant( "ends" ) ); 610 q.addConstraint( provided ); 611 Expression e2 = (Expression) q.getConstraints().iterator().next(); 612 assertEquals( desired, e2 ); 613 } 614 615 public void testRewriteContainsExpression() 616 { 617 Query q = new Query(); 618 Expression L = constant( "x" ); 619 Expression R = createSimplePattern( "contains" ); 620 Expression provided = dyadic( L, "Q_StringMatch", R ); 621 Expression desired = dyadic( L, "J_contains", constant( "contains" ) ); 622 q.addConstraint( provided ); 623 Expression e2 = (Expression) q.getConstraints().iterator().next(); 624 assertEquals( desired, e2 ); 625 } 626 627 public void testRewriteContainsInsensitiveExpression() 628 { 629 Query q = new Query(); 630 Expression L = constant( "x" ); 631 Expression R = createModifiedPattern( "coNtaIns", "i" ); 632 Expression provided = dyadic( L, "Q_StringMatch", R ); 633 Expression desired = dyadic( L, "J_containsInsensitive", constant( "contains" ) ); 634 q.addConstraint( provided ); 635 Expression e2 = (Expression) q.getConstraints().iterator().next(); 636 assertEquals( desired, e2 ); 637 } 638 639 protected static class BangException extends JenaException 640 { 641 public BangException() { super( "bang!" ); } 642 } 643 644 public void testQueryExceptionCleanlyExits() 645 { 646 Query q = new Query().addMatch( Triple.ANY ); 647 Graph g = new GraphBase() 648 { 649 protected ExtendedIterator graphBaseFind( TripleMatch m ) 650 { throw new BangException(); } 651 }; 652 ExtendedIterator it = eb( g, q, new Node[] {} ); 653 try { it.next(); fail( "should fail because graph explodes" ); } 654 catch (QueryStageException e) { assertTrue( e.getCause() instanceof BangException ); } 655 catch (Exception e) { fail( "should throw QueryStageException" ); } 656 } 657 658 protected static class PL extends Expression.Fixed implements PatternLiteral 659 { 660 protected String modifiers = ""; 661 public PL( String content ) { super( content ); } 662 public PL( String content, String modifiers ) { super( content ); this.modifiers = modifiers; } 663 public String getPatternString() { return (String ) value; } 664 public String getPatternModifiers() { return modifiers; } 665 public String getPatternLanguage() { return rdql; } 666 } 667 668 public Expression createSimplePattern( final String p ) 669 { return new PL( p ); } 670 671 public Expression createModifiedPattern( String content, String modifiers ) 672 { return new PL( content, modifiers ); } 673 674 private Expression constant( final Object it ) 675 { return new Expression.Fixed( it ); } 676 677 private Expression dyadic( Expression l, String op, Expression r ) 678 { 679 final String f = ExpressionFunctionURIs.prefix + op; 680 return new Dyadic( l, f, r ) 681 { 682 public boolean evalBool( Object l, Object r ) 683 { return false; } 684 }; 685 } 686 687 691 public void testTripleSorting() 692 { 693 Graph g = dataGraph(); 694 Map answer = getAnswer( g, TripleSorter.dontSort ); 695 assertEquals( 1, answer.size() ); 696 assertEquals( new Integer (1), answer.get( Arrays.asList( nodes( "a d" ) ) ) ); 697 698 assertEquals( answer, getAnswer( g, TripleSorter.dontSort ) ); 699 assertEquals( answer, getAnswer( g, fiddle( 0, 2, 1 ) ) ); 700 assertEquals( answer, getAnswer( g, fiddle( 1, 0, 2 ) ) ); 701 assertEquals( answer, getAnswer( g, fiddle( 1, 2, 0 ) ) ); 702 assertEquals( answer, getAnswer( g, fiddle( 2, 1, 0 ) ) ); 703 assertEquals( answer, getAnswer( g, fiddle( 2, 0, 1 ) ) ); 704 } 705 706 protected TripleSorter fiddle( final int a, final int b, final int c ) 707 { 708 return new TripleSorter() 709 { 710 public Triple [] sort( Triple [] triples ) 711 { return new Triple[] {triples[a], triples[b], triples[c]}; } 712 }; 713 } 714 715 protected Graph dataGraph() 716 { 717 Graph result = getGraph(); 718 graphAdd( result, "a SPOO d; a X b; b Y c" ); 719 return result; 720 } 721 722 protected Map getAnswer( Graph g, TripleSorter sorter ) 723 { 724 Map result = CollectionFactory.createHashedMap(); 725 Query q = new Query(); 726 q.addMatch( triple( "?a ?? ?d " ) ).addMatch( triple( "?a X ?b" ) ).addMatch( triple( "?b Y ?c" ) ); 727 q.addConstraint( notEqual( node( "?d" ), node( "?b" ) ) ); 728 Node [] answers = nodes( "?a ?d" ); 729 q.setTripleSorter( sorter ); 730 ExtendedIterator it = eb( g, q, answers ); 731 while (it.hasNext()) addAnswer( result, (List) it.next(), answers.length ); 732 return result; 733 } 734 735 protected void addAnswer( Map result, List bindings, int limit ) 736 { 737 List key = bindings.subList( 0, limit ); 738 Integer already = (Integer ) result.get( key ); 739 if (already == null) already = new Integer ( 0 ); 740 result.put( key, new Integer ( already.intValue() + 1 ) ); 741 } 742 743 public void testQueryOptimisation() 744 { 745 int dontCount = queryCount( TripleSorter.dontSort ); 746 int optimCount = queryCount( new SimpleTripleSorter() ); 747 if (optimCount > dontCount) 749 fail( "optimisation " + optimCount + " yet plain " + dontCount ); 750 } 751 752 int queryCount( TripleSorter sort ) 753 { 754 CountingGraph g = bigCountingGraph(); 755 for (int a = 0; a < 10; a += 1) 756 for (int b = 0; b < 10; b += 1) 757 for (int X = 0; X < 3; X += 1) 758 graphAdd( g, "a" + a + " X" + (X == 0 ? "" : X + "") + " b" + b ); 759 graphAdd( g, "a SPOO d; a X b; b Y c" ); 760 getAnswer( g, sort ); 761 return g.getCount(); 762 } 763 764 static class CountingGraph extends WrappedGraph 765 { 766 int counter; 767 private QueryHandler qh; 768 public QueryHandler queryHandler( ) { return qh; } 769 CountingGraph( Graph base ) 770 { super( base ); qh = new SimpleQueryHandler( this ); } 771 public ExtendedIterator find( Node s, Node p, Node o ) 772 { return find( Triple.createMatch( s, p, o ) ); } 773 public ExtendedIterator find( TripleMatch tm ) 774 { return count( base.find( tm ) ); } 775 ExtendedIterator count( ExtendedIterator it ) 776 { 777 return new WrappedIterator( it ) 778 { 779 public Object next() { try { return super.next(); } finally { counter += 1; } } 780 }; 781 } 782 int getCount() 783 { return counter; } 784 public String toString() 785 { return base.toString(); } 786 } 787 788 CountingGraph bigCountingGraph() 789 { 790 Graph bigGraph = getGraph(); 791 return new CountingGraph( bigGraph ); 792 } 793 } 794 795 796 | Popular Tags |