diff options
author | Vegard Sjonfjell <vegardsjo@gmail.com> | 2016-10-05 16:18:23 +0200 |
---|---|---|
committer | Vegard Sjonfjell <vegardsjo@gmail.com> | 2016-10-07 12:50:54 +0200 |
commit | 7141a841b0bd85342732072a235c45b78d896fba (patch) | |
tree | 1981275dc938af38278b947531ede7bcf9646e0f | |
parent | 92fa424e133b6da2e9d3b49231abf92e3adaa762 (diff) |
Revert "Revert "Voffeloff/constant tensor validation""
15 files changed, 436 insertions, 62 deletions
diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/RankingConstant.java b/config-model/src/main/java/com/yahoo/searchdefinition/RankingConstant.java index 2a4e231dee4..5b3ce7136d5 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/RankingConstant.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/RankingConstant.java @@ -26,6 +26,7 @@ public class RankingConstant { public String getName() { return name; } public String getFileName() { return fileName; } public String getFileReference() { return fileRef; } + public TensorType getTensorType() { return tensorType; } public String getType() { return tensorType.toString(); } public void validate() { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/ConstantTensorJsonValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/ConstantTensorJsonValidator.java new file mode 100644 index 00000000000..0485750bc16 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/ConstantTensorJsonValidator.java @@ -0,0 +1,191 @@ +package com.yahoo.vespa.model.application.validation; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.google.common.base.Joiner; +import com.yahoo.tensor.TensorType; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author Vegard Sjonfjell + */ +public class ConstantTensorJsonValidator { + static private final JsonFactory jsonFactory = new JsonFactory(); + private TensorType tensorType; + private JsonParser parser; + + public static class InvalidConstantTensor extends RuntimeException { + public InvalidConstantTensor(JsonParser parser, String message) { + super(message + " " + parser.getCurrentLocation().toString()); + } + + public InvalidConstantTensor(JsonParser parser, Exception base) { + super("Failed to parse JSON stream " + parser.getCurrentLocation().toString(), base); + } + } + + @FunctionalInterface + private static interface SubroutineThrowingIOException { + void invoke() throws IOException; + } + + private void wrapIOException(SubroutineThrowingIOException lambda) { + try { + lambda.invoke(); + } catch (IOException e) { + throw new InvalidConstantTensor(parser, e); + } + } + + public ConstantTensorJsonValidator(Reader tensorFile, TensorType tensorType) { + wrapIOException(() -> { + this.parser = jsonFactory.createParser(tensorFile); + this.tensorType = tensorType; + }); + } + + public void validate() { + wrapIOException(() -> { + assertNextTokenIs(JsonToken.START_OBJECT); + assertNextTokenIs(JsonToken.FIELD_NAME); + assertFieldNameIs("cells"); + + assertNextTokenIs(JsonToken.START_ARRAY); + + while (parser.nextToken() != JsonToken.END_ARRAY) { + validateTensorCell(tensorType.dimensions()); + } + + assertNextTokenIs(JsonToken.END_OBJECT); + }); + } + + private void validateTensorCell(Collection<TensorType.Dimension> tensorDimensions) { + wrapIOException(() -> { + assertCurrentTokenIs(JsonToken.START_OBJECT); + + final List<String> fieldNameCandidates = new ArrayList<>(Arrays.asList("address", "value")); + for (int i = 0; i < 2; i++) { + assertNextTokenIs(JsonToken.FIELD_NAME); + final String fieldName = parser.getCurrentName(); + + if (fieldNameCandidates.contains(fieldName)) { + fieldNameCandidates.remove(fieldName); + + if (fieldName.equals("address")) { + validateTensorAddress(tensorDimensions); + } else if (fieldName.equals("value")) { + validateTensorValue(); + } + } else { + throw new InvalidConstantTensor(parser, "Only \"address\" or \"value\" fields are permitted within a cell object"); + } + } + + assertNextTokenIs(JsonToken.END_OBJECT); + }); + } + + private void validateTensorAddress(Collection<TensorType.Dimension> tensorDimensions) throws IOException { + assertNextTokenIs(JsonToken.START_OBJECT); + + final Map<String, TensorType.Dimension> tensorDimensionsMapping = tensorDimensions.stream() + .collect(Collectors.toMap(TensorType.Dimension::name, Function.identity())); + + // Iterate within the address key, value pairs + while ((parser.nextToken() != JsonToken.END_OBJECT)) { + assertCurrentTokenIs(JsonToken.FIELD_NAME); + + final String dimensionName = parser.getCurrentName(); + TensorType.Dimension dimension = tensorDimensionsMapping.get(dimensionName); + if (dimension == null) { + throw new InvalidConstantTensor(parser, String.format("Tensor dimension with name \"%s\" does not exist", parser.getCurrentName())); + } + + tensorDimensionsMapping.remove(dimensionName); + validateTensorCoordinate(dimension); + } + + if (!tensorDimensionsMapping.isEmpty()) { + throw new InvalidConstantTensor(parser, String.format("Tensor address missing dimension(s): %s", Joiner.on(", ").join(tensorDimensionsMapping.keySet()))); + } + } + + /* + * Tensor coordinates are always strings. Coordinates for a mapped dimension can be any string, + * but those for indexed dimensions needs to be able to be interpreted as integers, and, + * additionally, those for indexed bounded dimensions needs to fall within the dimension size. + */ + private void validateTensorCoordinate(TensorType.Dimension dimension) throws IOException { + assertNextTokenIs(JsonToken.VALUE_STRING); + + if (dimension instanceof TensorType.IndexedBoundDimension) { + validateBoundedCoordinate((TensorType.IndexedBoundDimension) dimension); + } else if (dimension instanceof TensorType.IndexedUnboundDimension) { + validateUnboundedCoordinate(dimension); + } + } + + private void validateBoundedCoordinate(TensorType.IndexedBoundDimension dimension) { + wrapIOException(() -> { + try { + final int value = Integer.parseInt(parser.getValueAsString()); + if (value >= dimension.size().get()) { + throwCoordinateOutsideBoundedDimension(parser.getValueAsString(), dimension.name()); + } + } catch (NumberFormatException e) { + throwCoordinateOutsideBoundedDimension(parser.getValueAsString(), dimension.name()); + } + }); + } + + private void throwCoordinateOutsideBoundedDimension(String value, String dimensionName) { + throw new InvalidConstantTensor(parser, String.format("Coordinate \"%s\" not within limits of bounded dimension %s", value, dimensionName)); + } + + private void validateUnboundedCoordinate(TensorType.Dimension dimension) { + wrapIOException(() -> { + try { + Integer.parseInt(parser.getValueAsString()); + } catch (NumberFormatException e) { + throw new InvalidConstantTensor(parser, String.format("Coordinate \"%s\" for dimension %s is not an integer", parser.getValueAsString(), dimension.name())); + } + }); + } + + private void validateTensorValue() throws IOException { + assertNextTokenIs(JsonToken.VALUE_NUMBER_FLOAT); + } + + private void assertCurrentTokenIs(JsonToken wantedToken) { + assertTokenIs(parser.getCurrentToken(), wantedToken); + } + + private void assertNextTokenIs(JsonToken wantedToken) throws IOException { + assertTokenIs(parser.nextToken(), wantedToken); + } + + private void assertTokenIs(JsonToken token, JsonToken wantedToken) { + if (token != wantedToken) { + throw new InvalidConstantTensor(parser, String.format("Expected JSON token %s, but got %s", wantedToken.toString(), token.toString())); + } + } + + private void assertFieldNameIs(String wantedFieldName) throws IOException { + final String actualFieldName = parser.getCurrentName(); + + if (!actualFieldName.equals(wantedFieldName)) { + throw new InvalidConstantTensor(parser, String.format("Expected field name \"%s\", got \"%s\"", wantedFieldName, actualFieldName)); + } + } +} diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ConstantTensorJsonValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ConstantTensorJsonValidatorTest.java new file mode 100644 index 00000000000..e43b1597f59 --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ConstantTensorJsonValidatorTest.java @@ -0,0 +1,207 @@ +package com.yahoo.vespa.model.application.validation; + +import com.yahoo.tensor.TensorType; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.io.Reader; +import java.io.StringReader; + +import static com.yahoo.test.json.JsonTestHelper.inputJson; +import static com.yahoo.vespa.model.application.validation.ConstantTensorJsonValidator.InvalidConstantTensor; + +public class ConstantTensorJsonValidatorTest { + private static Reader inputJsonToReader(String... lines) { + return new StringReader(inputJson(lines)); + } + + private static void validateTensorJson(TensorType tensorType, Reader jsonTensorReader) { + ConstantTensorJsonValidator validator = new ConstantTensorJsonValidator(jsonTensorReader, tensorType); + validator.validate(); + } + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void ensure_that_unbounded_tensor_works() { + validateTensorJson( + TensorType.fromSpec("tensor(x[], y[])"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': '99999', 'y': '47' },", + " 'value': 9932.0", + " }", + " ]", + "}")); + } + + @Test + public void ensure_that_bounded_tensor_within_limits_works() { + validateTensorJson( + TensorType.fromSpec("tensor(x[5], y[10])"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': '3', 'y': '2' },", + " 'value': 2.0", + " }", + " ]", + "}")); + } + + @Test + public void ensure_that_multiple_cells_work() { + validateTensorJson( + TensorType.fromSpec("tensor(x[], y[])"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': '3', 'y': '2' },", + " 'value': 2.0", + " },", + " {", + " 'address': { 'x': '2', 'y': '0' },", + " 'value': 4.5", + " }", + " ]", + "}")); + } + + + @Test + public void ensure_that_no_cells_work() { + validateTensorJson( + TensorType.fromSpec("tensor(x[], y[])"), + inputJsonToReader( + "{", + " 'cells': []", + "}")); + } + + @Test + public void ensure_that_bounded_tensor_outside_limits_is_disallowed() { + expectedException.expect(InvalidConstantTensor.class); + expectedException.expectMessage("Coordinate \"9\" not within limits of bounded dimension x"); + + validateTensorJson( + TensorType.fromSpec("tensor(x[5], y[10])"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': '9', 'y': '2' },", + " 'value': 1e47", + " }", + " ]", + "}")); + } + + @Test + public void ensure_that_mapped_tensor_works() { + validateTensorJson( + TensorType.fromSpec("tensor(x{}, y{})"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': 'andrei', 'y': 'bjarne' },", + " 'value': 2.0", + " }", + " ]", + "}")); + } + + @Test + public void ensure_that_non_integer_strings_in_address_points_are_disallowed() { + expectedException.expect(InvalidConstantTensor.class); + expectedException.expectMessage("Coordinate \"a\" for dimension x is not an integer"); + + validateTensorJson( + TensorType.fromSpec("tensor(x[])"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': 'a' },", + " 'value': 47.0", + " }", + " ]", + "}")); + + } + + @Test + public void ensure_that_missing_coordinates_fail() { + expectedException.expect(InvalidConstantTensor.class); + expectedException.expectMessage("Tensor address missing dimension(s): y, z"); + + validateTensorJson( + TensorType.fromSpec("tensor(x[], y[], z[])"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': '3' },", + " 'value': 99.3", + " }", + " ]", + "}")); + } + + @Test + public void ensure_that_extra_dimensions_are_disallowed() { + expectedException.expect(InvalidConstantTensor.class); + expectedException.expectMessage("Tensor dimension with name \"z\" does not exist"); + + validateTensorJson( + TensorType.fromSpec("tensor(x[], y[])"), + inputJsonToReader( + "{", + " 'cells': [", + " {", + " 'address': { 'x': '3', 'y': '2', 'z': '4' },", + " 'value': 99.3", + " }", + " ]", + "}")); + } + + @Test + public void ensure_that_invalid_json_fails() { + expectedException.expect(InvalidConstantTensor.class); + expectedException.expectMessage("Failed to parse JSON stream"); + + validateTensorJson( + TensorType.fromSpec("tensor(x[], y[])"), + inputJsonToReader( + "{", + " cells': [", + " {", + " 'address': { 'x': '3' 'y': '2' }", + " 'value': 2.0", + " }", + " ", + "}")); + } + + @Test + public void ensure_that_invalid_json_not_in_tensor_format_fails() { + expectedException.expect(InvalidConstantTensor.class); + expectedException.expectMessage("Expected field name \"cells\", got \"stats\""); + + validateTensorJson(TensorType.fromSpec("tensor(x[], y[])"), + inputJsonToReader( + "{", + " 'stats': {", + " 'grandma-surprise': true,", + " 'points': 47", + " }", + "}")); + } +}
\ No newline at end of file diff --git a/config/pom.xml b/config/pom.xml index 73c8cd5b5ad..3518426a7bd 100755 --- a/config/pom.xml +++ b/config/pom.xml @@ -62,11 +62,6 @@ <scope>test</scope> </dependency> <dependency> - <groupId>uk.co.datumedge</groupId> - <artifactId>hamcrest-json</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>13.0.1</version> diff --git a/config/src/test/java/com/yahoo/config/subscription/CfgConfigPayloadBuilderTest.java b/config/src/test/java/com/yahoo/config/subscription/CfgConfigPayloadBuilderTest.java index 7ad7144a1c8..2bc1a10b729 100644 --- a/config/src/test/java/com/yahoo/config/subscription/CfgConfigPayloadBuilderTest.java +++ b/config/src/test/java/com/yahoo/config/subscription/CfgConfigPayloadBuilderTest.java @@ -11,8 +11,8 @@ import org.junit.Test; import java.util.Arrays; import java.util.List; -import static com.yahoo.config.subscription.util.JsonHelper.assertJsonEquals; -import static com.yahoo.config.subscription.util.JsonHelper.inputJson; +import static com.yahoo.test.json.JsonTestHelper.assertJsonEquals; +import static com.yahoo.test.json.JsonTestHelper.inputJson; import static org.junit.Assert.assertEquals; /** diff --git a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceSerializerTest.java b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceSerializerTest.java index d3713eaa401..342e50821f4 100644 --- a/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceSerializerTest.java +++ b/config/src/test/java/com/yahoo/config/subscription/ConfigInstanceSerializerTest.java @@ -1,22 +1,21 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.config.subscription; -import com.yahoo.foo.ArraytypesConfig; import com.yahoo.config.ConfigInstance; +import com.yahoo.foo.ArraytypesConfig; +import com.yahoo.foo.MaptypesConfig; import com.yahoo.foo.SimpletypesConfig; import com.yahoo.foo.SpecialtypesConfig; import com.yahoo.foo.StructtypesConfig; -import com.yahoo.foo.MaptypesConfig; import com.yahoo.slime.JsonFormat; import com.yahoo.slime.Slime; - import org.junit.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; -import static com.yahoo.config.subscription.util.JsonHelper.assertJsonEquals; -import static com.yahoo.config.subscription.util.JsonHelper.inputJson; +import static com.yahoo.test.json.JsonTestHelper.assertJsonEquals; +import static com.yahoo.test.json.JsonTestHelper.inputJson; import static org.junit.Assert.fail; /** diff --git a/config/src/test/java/com/yahoo/config/subscription/util/JsonHelper.java b/config/src/test/java/com/yahoo/config/subscription/util/JsonHelper.java deleted file mode 100644 index 27ac1a1278c..00000000000 --- a/config/src/test/java/com/yahoo/config/subscription/util/JsonHelper.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.config.subscription.util; - -import com.google.common.base.Joiner; - -import static org.hamcrest.MatcherAssert.assertThat; -import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; - -/** - * @author Vegard Sjonfjell - */ -public class JsonHelper { - /** - * Convenience method to input JSON without escaping double quotes and newlines - * Each parameter represents a line of JSON encoded data - * The lines are joined with newline and single quotes are replaced with double quotes - */ - public static String inputJson(String... lines) { - return Joiner.on("\n").join(lines).replaceAll("'", "\""); - } - - /** - * Structurally compare two JSON encoded strings - */ - public static void assertJsonEquals(String inputJson, String expectedJson) { - assertThat(inputJson, sameJSONAs(expectedJson)); - } -} diff --git a/document/pom.xml b/document/pom.xml index 529107407ca..71713b27050 100644 --- a/document/pom.xml +++ b/document/pom.xml @@ -48,11 +48,6 @@ <scope>test</scope> </dependency> <dependency> - <groupId>uk.co.datumedge</groupId> - <artifactId>hamcrest-json</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>com.yahoo.vespa</groupId> <artifactId>config</artifactId> <version>${project.version}</version> @@ -83,6 +78,12 @@ <classifier>no_aop</classifier> <scope>provided</scope> </dependency> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>testutil</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/document/src/main/java/com/yahoo/document/json/JsonWriter.java b/document/src/main/java/com/yahoo/document/json/JsonWriter.java index 626c97a958a..420a6bb6669 100644 --- a/document/src/main/java/com/yahoo/document/json/JsonWriter.java +++ b/document/src/main/java/com/yahoo/document/json/JsonWriter.java @@ -112,6 +112,7 @@ public class JsonWriter implements DocumentWriter { Map.Entry<Field, FieldValue> entry = i.next(); entry.getValue().serialize(entry.getKey(), this); } + generator.writeEndObject(); generator.writeEndObject(); generator.flush(); diff --git a/document/src/test/java/com/yahoo/document/json/DocumentUpdateJsonSerializerTest.java b/document/src/test/java/com/yahoo/document/json/DocumentUpdateJsonSerializerTest.java index b3deae547ab..de483186d6c 100644 --- a/document/src/test/java/com/yahoo/document/json/DocumentUpdateJsonSerializerTest.java +++ b/document/src/test/java/com/yahoo/document/json/DocumentUpdateJsonSerializerTest.java @@ -19,8 +19,8 @@ import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import static com.yahoo.document.json.JsonTestHelper.assertJsonEquals; -import static com.yahoo.document.json.JsonTestHelper.inputJson; +import static com.yahoo.test.json.JsonTestHelper.assertJsonEquals; +import static com.yahoo.test.json.JsonTestHelper.inputJson; /** * @author Vegard Sjonfjell diff --git a/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java b/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java index 466a915f83f..206ab8e30f0 100644 --- a/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java +++ b/document/src/test/java/com/yahoo/document/json/JsonReaderTestCase.java @@ -59,7 +59,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; -import static com.yahoo.document.json.JsonTestHelper.inputJson; +import static com.yahoo.test.json.JsonTestHelper.inputJson; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.*; diff --git a/testutil/pom.xml b/testutil/pom.xml index 0d2aa8a4dbf..bd46d2e4c16 100644 --- a/testutil/pom.xml +++ b/testutil/pom.xml @@ -15,6 +15,11 @@ <description>Library of useful Hamcrest matchers.</description> <dependencies> <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> <scope>compile</scope> @@ -25,6 +30,11 @@ <scope>compile</scope> </dependency> <dependency> + <groupId>uk.co.datumedge</groupId> + <artifactId>hamcrest-json</artifactId> + <scope>compile</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>compile</scope> diff --git a/document/src/test/java/com/yahoo/document/json/JsonTestHelper.java b/testutil/src/main/java/com/yahoo/test/json/JsonTestHelper.java index 09e6a74e68a..a8e8e562b2d 100644 --- a/document/src/test/java/com/yahoo/document/json/JsonTestHelper.java +++ b/testutil/src/main/java/com/yahoo/test/json/JsonTestHelper.java @@ -1,8 +1,9 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.document.json; +package com.yahoo.test.json; import com.google.common.base.Joiner; -import static org.hamcrest.MatcherAssert.assertThat; +import org.hamcrest.MatcherAssert; + import static uk.co.datumedge.hamcrest.json.SameJSONAs.sameJSONAs; /** @@ -23,7 +24,6 @@ public class JsonTestHelper { * Structurally compare two JSON encoded strings */ public static void assertJsonEquals(String inputJson, String expectedJson) { - assertThat(inputJson, sameJSONAs(expectedJson)); + MatcherAssert.assertThat(inputJson, sameJSONAs(expectedJson)); } - } diff --git a/vespa-http-client/pom.xml b/vespa-http-client/pom.xml index 9e2325e8016..563e4406fe9 100644 --- a/vespa-http-client/pom.xml +++ b/vespa-http-client/pom.xml @@ -83,6 +83,12 @@ <artifactId>airline</artifactId> <version>0.6</version> </dependency> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>testutil</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/runner/JsonReaderTest.java b/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/runner/JsonReaderTest.java index ab7dca0d5fb..eba8791bbb7 100644 --- a/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/runner/JsonReaderTest.java +++ b/vespa-http-client/src/test/java/com/yahoo/vespa/http/client/runner/JsonReaderTest.java @@ -1,7 +1,6 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.http.client.runner; -import com.google.common.base.Joiner; import com.yahoo.vespa.http.client.FeedClient; import com.yahoo.vespa.http.client.core.JsonReader; import org.junit.Test; @@ -13,6 +12,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import static com.yahoo.test.json.JsonTestHelper.inputJson; import static org.hamcrest.core.Is.is; import static org.junit.Assert.*; @@ -260,13 +260,4 @@ public class JsonReaderTest { assertThat(session.documentIds.size(), is(1)); assertThat(session.documentIds.get(0), is("id:foo:music:doc:foo:bar")); } - - /** - * Convenience method to input JSON without escaping double quotes and newlines - * Each parameter represents a line of JSON encoded data - * The lines are joined with newline and single quotes are replaced with double quotes - */ - static String inputJson(String... lines) { - return Joiner.on("\n").join(lines).replaceAll("'", "\""); - } }
\ No newline at end of file |