From fc2bc3648a2df2f58e008b01f89481b745272695 Mon Sep 17 00:00:00 2001 From: Mats Rydberg Date: Thu, 25 Feb 2016 15:46:57 +0100 Subject: [PATCH] Add matcher for relationships --- .../feature/parser/CypherMatchersCreator.java | 54 ++++--------------- .../parser/matchers/RelationshipMatcher.java | 53 ++++++++++++++++++ .../feature/parser/ParsingTestSupport.scala | 31 ++++++++++- .../parser/expectedResultsParserTest.scala | 6 +-- .../matchers/RelationshipMatcherTest.scala | 46 ++++++++++++++++ 5 files changed, 142 insertions(+), 48 deletions(-) create mode 100644 community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/RelationshipMatcher.java create mode 100644 community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/RelationshipMatcherTest.scala diff --git a/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/CypherMatchersCreator.java b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/CypherMatchersCreator.java index 0316f03dd5f0f..0544b22e24b05 100644 --- a/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/CypherMatchersCreator.java +++ b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/CypherMatchersCreator.java @@ -21,14 +21,7 @@ import cypher.feature.parser.generated.FeatureResultsBaseListener; import cypher.feature.parser.generated.FeatureResultsParser; -import cypher.feature.parser.matchers.BooleanMatcher; -import cypher.feature.parser.matchers.FloatMatcher; -import cypher.feature.parser.matchers.IntegerMatcher; -import cypher.feature.parser.matchers.ListMatcher; -import cypher.feature.parser.matchers.MapMatcher; -import cypher.feature.parser.matchers.NodeMatcher; -import cypher.feature.parser.matchers.StringMatcher; -import cypher.feature.parser.matchers.ValueMatcher; +import cypher.feature.parser.matchers.*; import java.util.Deque; import java.util.HashMap; @@ -37,14 +30,12 @@ import java.util.Map; import java.util.Set; -import org.neo4j.graphdb.RelationshipType; - class CypherMatchersCreator extends FeatureResultsBaseListener { - private Deque oldworkload; private Deque workload; private Deque listCounters; private Deque mapCounters; + private Deque keys; private Deque names; private static final String INFINITY = "Inf"; @@ -52,7 +43,7 @@ class CypherMatchersCreator extends FeatureResultsBaseListener CypherMatchersCreator() { this.workload = new LinkedList<>(); - this.oldworkload = new LinkedList<>(); + this.keys = new LinkedList<>(); this.listCounters = new LinkedList<>(); this.mapCounters = new LinkedList<>(); this.names = new LinkedList<>(); @@ -150,16 +141,16 @@ public void exitPropertyMap( FeatureResultsParser.PropertyMapContext ctx ) for ( int i = 0; i < counter; ++i ) { ValueMatcher value = workload.pop(); - String key = oldworkload.pop().toString(); + String key = keys.pop(); map.put( key, value ); } - workload.push( new MapMatcher(map) ); + workload.push( new MapMatcher( map ) ); } @Override public void enterPropertyKey( FeatureResultsParser.PropertyKeyContext ctx ) { - oldworkload.push( ctx.getText() ); + keys.push( ctx.getText() ); } @Override @@ -176,23 +167,11 @@ public void exitNode( FeatureResultsParser.NodeContext ctx ) Set labelNames = new HashSet<>(); while ( !names.isEmpty() ) { - labelNames.add( names.pop() ); + labelNames.add( names.pop() ); } workload.push( new NodeMatcher( labelNames, properties ) ); } - private Map getMapOrEmpty() - { - if ( oldworkload.isEmpty() ) - { - return new HashMap<>(); - } - else - { - return (Map) oldworkload.pop(); - } - } - private MapMatcher getMapMatcher() { if ( workload.isEmpty() ) @@ -214,21 +193,8 @@ public void enterRelationshipTypeName( FeatureResultsParser.RelationshipTypeName @Override public void exitRelationship( FeatureResultsParser.RelationshipContext ctx ) { - final Map properties = getMapOrEmpty(); - final RelationshipType type = RelationshipType.withName( names.pop() ); - oldworkload.push( new ParsedRelationship() - { - @Override - public RelationshipType getType() - { - return type; - } - - @Override - public Map getAllProperties() - { - return properties; - } - } ); + MapMatcher properties = getMapMatcher(); + String relTypeName = names.pop(); + workload.push( new RelationshipMatcher( relTypeName, properties ) ); } } diff --git a/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/RelationshipMatcher.java b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/RelationshipMatcher.java new file mode 100644 index 0000000000000..c92f00e549e24 --- /dev/null +++ b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/RelationshipMatcher.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2002-2016 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cypher.feature.parser.matchers; + +import org.neo4j.graphdb.Relationship; + +public class RelationshipMatcher implements ValueMatcher +{ + private final String relationshipTypeName; + private final MapMatcher propertyMatcher; + + public RelationshipMatcher( String relationshipTypeName, MapMatcher propertyMatcher ) + { + this.relationshipTypeName = relationshipTypeName; + this.propertyMatcher = propertyMatcher; + } + + @Override + public boolean matches( Object value ) + { + if ( value instanceof Relationship ) + { + Relationship relationship = (Relationship) value; + + return relationship.getType().name().equals( relationshipTypeName ) + && propertyMatcher.matches( relationship.getAllProperties() ); + } + return false; + } + + @Override + public String toString() + { + return "RelationshipMatcher for type " + relationshipTypeName + " and properties: " + propertyMatcher; + } +} diff --git a/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/ParsingTestSupport.scala b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/ParsingTestSupport.scala index 920405b8374cc..6856b07a253f2 100644 --- a/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/ParsingTestSupport.scala +++ b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/ParsingTestSupport.scala @@ -1,8 +1,27 @@ +/* + * Copyright (c) 2002-2016 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ package cypher.feature.parser import cypher.feature.parser.matchers.ValueMatcher import org.mockito.Mockito._ -import org.neo4j.graphdb.{Label, Node} +import org.neo4j.graphdb.{RelationshipType, Relationship, Label, Node} import org.scalatest.{Matchers, FunSuite} import org.scalatest.matchers.{MatchResult, Matcher} @@ -14,8 +33,18 @@ class ParsingTestSupport extends FunSuite with Matchers with DecorateAsJava { val node = mock(classOf[Node]) when(node.getLabels).thenReturn(labels.map(Label.label).toIterable.asJava) when(node.getAllProperties).thenReturn(properties.asJava) + when(node.toString).thenReturn(s"(${labels.mkString(":", ":", "")} $properties)") node } + + def relationship(typ: String, properties: Map[String, AnyRef] = Map.empty): Relationship = { + val rel = mock(classOf[Relationship]) + when(rel.getType).thenReturn(RelationshipType.withName(typ)) + when(rel.getAllProperties).thenReturn(properties.asJava) + when(rel.toString).thenReturn(s"[:$typ $properties]") + rel + } + case class accept(value: Any) extends Matcher[ValueMatcher] { override def apply(matcher: ValueMatcher): MatchResult = { diff --git a/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/expectedResultsParserTest.scala b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/expectedResultsParserTest.scala index 4d89dd03d0cce..aa6c610d046a2 100644 --- a/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/expectedResultsParserTest.scala +++ b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/expectedResultsParserTest.scala @@ -34,7 +34,7 @@ import org.scalatest.{FunSuite, Matchers} class expectedResultsParserTest extends ParsingTestSupport { test("should parse null") { - valueParse("null") should equal(null) + parse("null") should accept(null) } test("should parse integer") { @@ -133,8 +133,8 @@ class expectedResultsParserTest extends ParsingTestSupport { } test("should parse relationships") { - valueParse("[:T]") should equal(parsedRelationship("T")) - valueParse("[:T {k:0}]") should equal(parsedRelationship("T", Map("k" -> Long.valueOf(0L)))) + parse("[:T]") should accept(relationship("T")) + parse("[:T {k:0}]") should accept(relationship("T", Map("k" -> Long.valueOf(0L)))) } // test("should parse the zero-length path") { diff --git a/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/RelationshipMatcherTest.scala b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/RelationshipMatcherTest.scala new file mode 100644 index 0000000000000..86d51a68bcf5e --- /dev/null +++ b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/RelationshipMatcherTest.scala @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2002-2016 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package cypher.feature.parser.matchers + +import cypher.feature.parser.ParsingTestSupport + +class RelationshipMatcherTest extends ParsingTestSupport { + + test("should match relationships") { + new RelationshipMatcher("T", MapMatcher.EMPTY) should accept(relationship("T")) + } + + test("should match relationships with properties") { + val matcher = new RelationshipMatcher("T", new MapMatcher(Map[String, ValueMatcher]("key" -> new FloatMatcher(1e10)).asJava)) + + matcher should accept(relationship("T", Map("key" -> java.lang.Double.valueOf(1e10)))) + } + + test("should not match other types") { + new RelationshipMatcher("T", MapMatcher.EMPTY) shouldNot accept(node()) + new RelationshipMatcher("T", MapMatcher.EMPTY) shouldNot accept(null) + new RelationshipMatcher("T", MapMatcher.EMPTY) shouldNot accept("relationship") + } + + test("should not match when different type") { + new RelationshipMatcher("type1", MapMatcher.EMPTY) shouldNot accept(relationship("type2")) + } + +}