From 2e18243f654c3cdb9b232255953198d3e952c225 Mon Sep 17 00:00:00 2001 From: Mats Rydberg Date: Wed, 18 May 2016 11:45:56 +0200 Subject: [PATCH] Refactor the TCK serialization of results --- .../parser/matchers/ResultWrapper.java | 100 +----------- .../parser/matchers/TckSerializer.java | 144 ++++++++++++++++++ .../parser/matchers/TckSerializerTest.scala | 49 ++++++ 3 files changed, 194 insertions(+), 99 deletions(-) create mode 100644 community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/TckSerializer.java create mode 100644 community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/TckSerializerTest.scala diff --git a/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/ResultWrapper.java b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/ResultWrapper.java index 3faa0ee7f0ab5..557df4b966fd1 100644 --- a/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/ResultWrapper.java +++ b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/ResultWrapper.java @@ -88,109 +88,11 @@ public Map next() Map next = inner.next(); builder.append( "[" ).append( rowCounter++ ).append( "] " ); builder.append( "actualRow:" ); - builder.append( serialize( next ) ); + builder.append( TckSerializer.serialize( next ) ); builder.append( "\n" ); return next; } - private String serialize( Object obj ) - { - StringBuilder sb = new StringBuilder(); - if ( obj == null ) - { - sb.append( "null" ); - } - else if ( obj instanceof Node ) - { - Node n = (Node) obj; - sb.append( "(" ); - n.getLabels().forEach( ( l ) -> sb.append( ":" ).append( l.name() ) ); - sb.append( " {" ); - String[] comma = new String[]{ "" }; - n.getAllProperties().forEach( ( k, v ) -> { - sb.append( comma[0] ).append( k ).append( ": " ).append( serialize( v ) ); - comma[0] = ", "; - } ); - sb.append( "})" ); - } - else if ( obj instanceof Relationship ) - { - Relationship r = (Relationship) obj; - sb.append( "[:" ); - sb.append( r.getType().name() ); - sb.append( " {" ); - String[] comma = new String[]{ "" }; - r.getAllProperties().forEach( ( k, v ) -> { - sb.append( comma[0] ).append( k ).append( ": " ).append( serialize( v ) ); - comma[0] = ", "; - } ); - sb.append( "}]" ); - } - else if ( obj instanceof Path ) - { - Path p = (Path) obj; - sb.append( "<" ); - sb.append( Paths.pathToString( p, new Paths.PathDescriptor() - { - @Override - public String nodeRepresentation( Path path, Node node ) - { - return serialize( node ); - } - - @Override - public String relationshipRepresentation( Path path, - Node from, Relationship relationship ) - { - String prefix = "-", suffix = "-"; - if ( from.equals( relationship.getEndNode() ) ) - { - prefix = "<-"; - } - else - { - suffix = "->"; - } - return prefix + serialize( relationship ) + suffix; - } - } ) ); - sb.append( ">" ); - } - else if ( obj instanceof String ) - { - sb.append( "'" ).append( obj.toString() ).append( "'" ); - } - else if ( obj instanceof List ) - { - List list = (List) obj; - List output = new ArrayList<>( list.size() ); - list.forEach( item -> output.add( serialize( item ) ) ); - sb.append( output ); - } - else if ( obj.getClass().isArray() ) - { - List list = new ArrayList<>(); - for ( int i = 0; i < Array.getLength( obj ); ++i ) - { - list.add( Array.get( obj, i ) ); - } - sb.append( serialize( list ) ); - } - else if ( obj instanceof Map ) - { - Map map = (Map) obj; - Map output = new HashMap<>( map.size() ); - map.forEach( ( k, v ) -> output.put( k.toString(), serialize( v ) ) ); - sb.append( output ); - } - else - { - sb.append( obj.toString() ); - } - - return sb.toString(); - } - @Override public void close() { diff --git a/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/TckSerializer.java b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/TckSerializer.java new file mode 100644 index 0000000000000..fa4ee6f647db0 --- /dev/null +++ b/community/cypher/compatibility-suite/src/main/java/cypher/feature/parser/matchers/TckSerializer.java @@ -0,0 +1,144 @@ +/* + * 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 java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Path; +import org.neo4j.graphdb.Relationship; +import org.neo4j.graphdb.traversal.Paths; + +class TckSerializer +{ + private final StringBuilder sb; + + private TckSerializer( ) + { + this.sb = new StringBuilder(); + } + + static String serialize( Object obj ) + { + return new TckSerializer().innerSerialize( obj ); + } + + private String innerSerialize( Object obj ) + { + if ( obj == null ) + { + sb.append( "null" ); + } + else if ( obj instanceof Node ) + { + Node n = (Node) obj; + sb.append( "(" ); + n.getLabels().forEach( ( l ) -> sb.append( ":" ).append( l.name() ) ); + sb.append( " {" ); + String[] comma = new String[]{ "" }; + n.getAllProperties().forEach( ( k, v ) -> { + sb.append( comma[0] ).append( k ).append( ": " ).append( serialize( v ) ); + comma[0] = ", "; + } ); + sb.append( "})" ); + } + else if ( obj instanceof Relationship ) + { + Relationship r = (Relationship) obj; + sb.append( "[:" ); + sb.append( r.getType().name() ); + sb.append( " {" ); + String[] comma = new String[]{ "" }; + r.getAllProperties().forEach( ( k, v ) -> { + sb.append( comma[0] ).append( k ).append( ": " ).append( serialize( v ) ); + comma[0] = ", "; + } ); + sb.append( "}]" ); + } + else if ( obj instanceof Path ) + { + Path p = (Path) obj; + sb.append( "<" ); + sb.append( Paths.pathToString( p, new Paths.PathDescriptor() + { + @Override + public String nodeRepresentation( Path path, Node node ) + { + return serialize( node ); + } + + @Override + public String relationshipRepresentation( Path path, + Node from, Relationship relationship ) + { + String prefix = "-", suffix = "-"; + if ( from.equals( relationship.getEndNode() ) ) + { + prefix = "<-"; + } + else + { + suffix = "->"; + } + return prefix + serialize( relationship ) + suffix; + } + } ) ); + sb.append( ">" ); + } + else if ( obj instanceof String ) + { + sb.append( "'" ).append( obj.toString() ).append( "'" ); + } + else if ( obj instanceof List ) + { + List list = (List) obj; + List output = new ArrayList<>( list.size() ); + list.forEach( item -> output.add( serialize( item ) ) ); + sb.append( output ); + } + else if ( obj.getClass().isArray() ) + { + List list = new ArrayList<>(); + for ( int i = 0; i < Array.getLength( obj ); ++i ) + { + list.add( Array.get( obj, i ) ); + } + sb.append( serialize( list ) ); + } + else if ( obj instanceof Map ) + { + Map map = (Map) obj; + Map output = new HashMap<>( map.size() ); + map.forEach( ( k, v ) -> output.put( k.toString(), serialize( v ) ) ); + sb.append( output ); + } + else + { + sb.append( obj.toString() ); + } + + return sb.toString(); + } + +} diff --git a/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/TckSerializerTest.scala b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/TckSerializerTest.scala new file mode 100644 index 0000000000000..67f741a632ff3 --- /dev/null +++ b/community/cypher/compatibility-suite/src/test/scala/cypher/feature/parser/matchers/TckSerializerTest.scala @@ -0,0 +1,49 @@ +/* + * 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 scala.collection.JavaConverters._ +import org.scalatest.{FunSuite, Matchers} + +class TckSerializerTest extends FunSuite with Matchers { + + test("should serialize primitives") { + serialize(true) should equal("true") + serialize(1) should equal("1") + serialize("1") should equal("'1'") + serialize(1.5) should equal("1.5") + serialize(null) should equal("null") + } + + test("should serialize lists") { + serialize(List.empty.asJava) should equal("[]") + serialize(List(1).asJava) should equal("[1]") + serialize(List("1", 1, 1.0).asJava) should equal("['1', 1, 1.0]") + serialize(List(List("foo").asJava).asJava) should equal("[['foo']]") + } + + test("should serialize maps") { + serialize(Map.empty.asJava) should equal("{}") + serialize(Map("key" -> true, "key2" -> 1000).asJava) should equal("{key2=1000, key=true}") + serialize(Map("key" -> Map("inner" -> 50.0).asJava, "key2" -> List("foo").asJava).asJava) should equal("{key2=['foo'], key={inner=50.0}}") + } + + private def serialize(v: Any) = TckSerializer.serialize(v) +}