/*
* (C) Copyright 2017 Nuxeo (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Kevin Leturc
*/
package org.nuxeo.ecm.automation.core.util;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.Blobs;
import org.nuxeo.ecm.core.api.model.Property;
import org.nuxeo.ecm.core.api.model.impl.DocumentPartImpl;
import org.nuxeo.ecm.core.api.model.impl.PropertyFactory;
import org.nuxeo.ecm.core.schema.Namespace;
import org.nuxeo.ecm.core.schema.TypeConstants;
import org.nuxeo.ecm.core.schema.types.ComplexType;
import org.nuxeo.ecm.core.schema.types.ComplexTypeImpl;
import org.nuxeo.ecm.core.schema.types.FieldImpl;
import org.nuxeo.ecm.core.schema.types.ListTypeImpl;
import org.nuxeo.ecm.core.schema.types.QName;
import org.nuxeo.ecm.core.schema.types.SchemaImpl;
import org.nuxeo.ecm.core.schema.types.Type;
import org.nuxeo.ecm.core.schema.types.primitives.BooleanType;
import org.nuxeo.ecm.core.schema.types.primitives.DateType;
import org.nuxeo.ecm.core.schema.types.primitives.DoubleType;
import org.nuxeo.ecm.core.schema.types.primitives.IntegerType;
import org.nuxeo.ecm.core.schema.types.primitives.LongType;
import org.nuxeo.ecm.core.schema.types.primitives.StringType;
import org.nuxeo.ecm.webengine.JsonFactoryManager;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.LocalDeploy;
import org.nuxeo.runtime.test.runner.RuntimeFeature;
/**
* @since 9.1
*/
@RunWith(FeaturesRunner.class)
@Features({ RuntimeFeature.class })
@LocalDeploy({ "org.nuxeo.ecm.webengine.core:OSGI-INF/json-service.xml" })
public class TestJSONPropertyWriter {
public static final String SCHEMA_NAME = "schema";
public static final SchemaImpl SCHEMA = new SchemaImpl(SCHEMA_NAME, new Namespace("", ""));
@Test
public void testWritePropertyWithNullProperty() throws IOException {
// write null
testWriteProperty(JSONPropertyWriter.create(), StringType.INSTANCE, null, "{\"property\":null}");
// don't write null
testWriteProperty(JSONPropertyWriter.create().writeNull(false), StringType.INSTANCE, null, "{}");
}
@Test
public void testWritePropertyWithBooleanProperty() throws IOException {
testWriteProperty(JSONPropertyWriter.create(), BooleanType.INSTANCE, Boolean.TRUE, "{\"property\":true}");
}
@Test
public void testWritePropertyWithLongProperty() throws IOException {
testWriteProperty(JSONPropertyWriter.create(), LongType.INSTANCE, Long.valueOf(10L), "{\"property\":10}");
}
@Test
public void testWritePropertyWithDoubleProperty() throws IOException {
testWriteProperty(JSONPropertyWriter.create(), DoubleType.INSTANCE, Double.valueOf(2.5), "{\"property\":2.5}");
}
@Test
@Ignore("PropertyFactory returns a LongProperty for IntegerType -> ClassCast exception")
public void testWritePropertyWithIntegerProperty() throws IOException {
testWriteProperty(JSONPropertyWriter.create(), IntegerType.INSTANCE, Integer.valueOf(2),
"{\"property\":\"string value\"}");
}
@Test
public void testWritePropertyWithDatePropertyDate() throws IOException {
Date value = new Date();
value.setTime(0L);
testWriteProperty(JSONPropertyWriter.create(), DateType.INSTANCE, value,
"{\"property\":\"1970-01-01T00:00:00.000Z\"}");
}
@Test
public void testWritePropertyWithDatePropertyDateInMillis() throws IOException {
Date value = new Date();
value.setTime(1_000L);
testWriteProperty(JSONPropertyWriter.create().dateTimeFormat(DateTimeFormat.TIME_IN_MILLIS), DateType.INSTANCE,
value, "{\"property\":1000}");
}
@Test
public void testWritePropertyWithDatePropertyCalendar() throws IOException {
Calendar value = Calendar.getInstance();
value.setTimeInMillis(0);
testWriteProperty(JSONPropertyWriter.create(), DateType.INSTANCE, value,
"{\"property\":\"1970-01-01T00:00:00.000Z\"}");
}
@Test
public void testWritePropertyWithDatePropertyCalendarInMillis() throws IOException {
Date value = new Date();
value.setTime(1_000L);
testWriteProperty(JSONPropertyWriter.create().dateTimeFormat(DateTimeFormat.TIME_IN_MILLIS), DateType.INSTANCE,
value, "{\"property\":1000}");
}
@Test
public void testWritePropertyWithStringProperty() throws IOException {
testWriteProperty(JSONPropertyWriter.create(), StringType.INSTANCE, "string value",
"{\"property\":\"string value\"}");
}
@Test
public void testWritePropertyWithArrayProperty() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
List<String> values = Arrays.asList("string1", "string2");
testWriteProperty(JSONPropertyWriter.create(), type, values, "{\"property\":[\"string1\",\"string2\"]}");
}
@Test
public void testWritePropertyWithArrayPropertyNullValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
// write empty
testWriteProperty(JSONPropertyWriter.create(), type, null, "{\"property\":[]}");
// don't write empty
testWriteProperty(JSONPropertyWriter.create().writeEmpty(false), type, null, "{}");
}
@Test
public void testWritePropertyWithArrayPropertyEmptyValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
testWriteProperty(JSONPropertyWriter.create(), type, new ArrayList<>(), "{\"property\":[]}");
}
@Test
public void testWritePropertyWithListProperty() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE, "string", null, 0, -1);
List<String> values = Arrays.asList("string1", "string2");
testWriteProperty(JSONPropertyWriter.create(), type, values, "{\"property\":[\"string1\",\"string2\"]}");
}
@Test
public void testWritePropertyWithListPropertyNullValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
// write empty
testWriteProperty(JSONPropertyWriter.create(), type, null, "{\"property\":[]}");
// don't write empty
testWriteProperty(JSONPropertyWriter.create().writeEmpty(false), type, null, "{}");
}
@Test
public void testWritePropertyWithListPropertyEmptyValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
// write empty
testWriteProperty(JSONPropertyWriter.create(), type, Collections.emptyList(), "{\"property\":[]}");
// don't write empty
testWriteProperty(JSONPropertyWriter.create().writeEmpty(false), type, Collections.emptyList(), "{}");
}
@Test
public void testWritePropertyWithMapProperty() throws IOException {
ComplexType type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, "complex");
type.addField("key1", StringType.INSTANCE, null, 0, null);
type.addField("key2", StringType.INSTANCE, null, 0, null);
Map<String, String> values = new HashMap<>();
values.put("key1", "value1");
values.put("key2", "value2");
testWriteProperty(JSONPropertyWriter.create(), type, values,
"{\"property\":{\"key1\":\"value1\",\"key2\":\"value2\"}}");
}
@Test
public void testWritePropertyWithMapPropertyNullValue() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, "complex");
// write empty
testWriteProperty(JSONPropertyWriter.create(), type, null, "{\"property\":{}}");
// don't write empty
testWriteProperty(JSONPropertyWriter.create().writeEmpty(false), type, null, "{}");
}
@Test
public void testWritePropertyWithMapPropertyEmptyValue() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, "complex");
// write empty
testWriteProperty(JSONPropertyWriter.create(), type, Collections.emptyMap(), "{\"property\":{}}");
// don't write empty
testWriteProperty(JSONPropertyWriter.create().writeEmpty(false), type, Collections.emptyMap(), "{}");
}
@Test
public void testWritePropertyWithBlobProperty() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, TypeConstants.CONTENT);
Blob value = Blobs.createBlob("content");
// write null
testWriteProperty(JSONPropertyWriter.create(), type, value,
"{\"property\":{\"name\":null,\"mime-type\":\"text/plain\",\"encoding\":\"UTF-8\","
+ "\"digest\":null,\"length\":7}}");
// don't write null
testWriteProperty(JSONPropertyWriter.create().writeNull(false), type, value,
"{\"property\":{\"mime-type\":\"text/plain\",\"encoding\":\"UTF-8\",\"length\":7}}");
}
@Test
public void testWritePropertyWithBlobPropertyWithFileBaseUrl() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, TypeConstants.CONTENT);
Blob value = Blobs.createBlob("content", "text/plain", "utf-8", "content.txt");
testWriteProperty(JSONPropertyWriter.create().filesBaseUrl("http://fileBaseUrl"), type, value,
"{\"property\":{\"name\":\"content.txt\",\"mime-type\":\"text/plain\",\"encoding\":\"utf-8\","
+ "\"digest\":null,\"length\":7,\"data\":\"http://fileBaseUrl/schema:property/content.txt\"}}");
}
@Test
public void testWritePropertyWithBlobPropertyNull() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, TypeConstants.CONTENT);
// write null
testWriteProperty(JSONPropertyWriter.create(), type, null, "{\"property\":null}");
// don't write null
testWriteProperty(JSONPropertyWriter.create().writeNull(false), type, null, "{}");
}
@Test
public void testWritePropertyValueWithNullProperty() throws IOException {
testWritePropertyValue(StringType.INSTANCE, null, "null");
}
@Test
public void testWritePropertyValueWithBooleanProperty() throws IOException {
testWritePropertyValue(BooleanType.INSTANCE, Boolean.TRUE, "true");
}
@Test
public void testWritePropertyValueWithLongProperty() throws IOException {
testWritePropertyValue(LongType.INSTANCE, Long.valueOf(10L), "10");
}
@Test
public void testWritePropertyValueWithDoubleProperty() throws IOException {
testWritePropertyValue(DoubleType.INSTANCE, Double.valueOf(2.5), "2.5");
}
@Test
@Ignore("PropertyFactory returns a LongProperty for IntegerType -> ClassCast exception")
public void testWritePropertyValueWithIntegerProperty() throws IOException {
testWritePropertyValue(IntegerType.INSTANCE, Integer.valueOf(2), "\"string value\"");
}
@Test
public void testWritePropertyValueWithDatePropertyDate() throws IOException {
Date value = new Date();
value.setTime(0L);
testWritePropertyValue(DateType.INSTANCE, value, "\"1970-01-01T00:00:00.000Z\"");
}
@Test
public void testWritePropertyValueWithDatePropertyDateInMillis() throws IOException {
Date value = new Date();
value.setTime(1_000L);
testWritePropertyValue(DateType.INSTANCE, value, "1000", DateTimeFormat.TIME_IN_MILLIS);
}
@Test
public void testWritePropertyValueWithDatePropertyCalendar() throws IOException {
Calendar value = Calendar.getInstance();
value.setTimeInMillis(0);
testWritePropertyValue(DateType.INSTANCE, value, "\"1970-01-01T00:00:00.000Z\"");
}
@Test
public void testWritePropertyValueWithDatePropertyCalendarInMillis() throws IOException {
Date value = new Date();
value.setTime(1_000L);
testWritePropertyValue(DateType.INSTANCE, value, "1000", DateTimeFormat.TIME_IN_MILLIS);
}
@Test
public void testWritePropertyValueWithStringProperty() throws IOException {
testWritePropertyValue(StringType.INSTANCE, "string value", "\"string value\"");
}
@Test
public void testWritePropertyValueWithArrayProperty() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
List<String> values = Arrays.asList("string1", "string2");
testWritePropertyValue(type, values, "[\"string1\",\"string2\"]");
}
@Test
public void testWritePropertyValueWithArrayPropertyNullValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
testWritePropertyValue(type, null, "[]");
}
@Test
public void testWritePropertyValueWithArrayPropertyEmptyValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
testWritePropertyValue(type, new ArrayList<>(), "[]");
}
@Test
public void testWritePropertyValueWithListProperty() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE, "string", null, 0, -1);
List<String> values = Arrays.asList("string1", "string2");
testWritePropertyValue(type, values, "[\"string1\",\"string2\"]");
}
@Test
public void testWritePropertyValueWithListPropertyNullValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
testWritePropertyValue(type, null, "[]");
}
@Test
public void testWritePropertyValueWithListPropertyEmptyValue() throws IOException {
Type type = new ListTypeImpl(SCHEMA_NAME, "strings", StringType.INSTANCE);
testWritePropertyValue(type, Collections.emptyList(), "[]");
}
@Test
public void testWritePropertyValueWithMapProperty() throws IOException {
ComplexType type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, "complex");
type.addField("key1", StringType.INSTANCE, null, 0, null);
type.addField("key2", StringType.INSTANCE, null, 0, null);
Map<String, String> values = new HashMap<>();
values.put("key1", "value1");
values.put("key2", "value2");
testWritePropertyValue(type, values, "{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
@Test
public void testWritePropertyValueWithMapPropertyNullValue() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, "complex");
testWritePropertyValue(type, null, "{}");
}
@Test
public void testWritePropertyValueWithMapPropertyEmptyValue() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, "complex");
testWritePropertyValue(type, Collections.emptyMap(), "{}");
}
@Test
public void testWritePropertyValueWithBlobProperty() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, TypeConstants.CONTENT);
Blob value = Blobs.createBlob("content");
testWritePropertyValue(type, value, "{\"name\":null,\"mime-type\":\"text/plain\",\"encoding\":\"UTF-8\","
+ "\"digest\":null,\"length\":7}");
}
@Test
public void testWritePropertyValueWithBlobPropertyWithFileBaseUrl() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, TypeConstants.CONTENT);
Blob value = Blobs.createBlob("content", "text/plain", "utf-8", "content.txt");
testWritePropertyValue(type, value,
"{\"name\":\"content.txt\",\"mime-type\":\"text/plain\",\"encoding\":\"utf-8\",\"digest\":null,"
+ "\"length\":7,\"data\":\"http://fileBaseUrl/schema:property/content.txt\"}",
"http://fileBaseUrl/");
}
@Test
public void testWritePropertyValueWithBlobPropertyNullValue() throws IOException {
Type type = new ComplexTypeImpl(SCHEMA, SCHEMA_NAME, TypeConstants.CONTENT);
testWritePropertyValue(type, null, "null");
}
protected void testWriteProperty(JSONPropertyWriter propertyWriter, Type type, Object value, String expectedValue)
throws IOException {
// Init generator
ByteArrayOutputStream out = new ByteArrayOutputStream();
JsonGenerator jg = getFactory().createJsonGenerator(out);
// Write value
Property property = createProperty(type, value);
jg.writeStartObject();
propertyWriter.writeProperty(jg, property);
jg.writeEndObject();
jg.flush();
jg.close();
String result = out.toString("UTF-8");
// Assert result
assertEquals(expectedValue, result);
}
protected void testWritePropertyValue(Type type, Object value, String expectedValue) throws IOException {
testWritePropertyValue(type, value, expectedValue, DateTimeFormat.W3C, null);
}
protected void testWritePropertyValue(Type type, Object value, String expectedValue, String filesBaseUrl)
throws IOException {
testWritePropertyValue(type, value, expectedValue, DateTimeFormat.W3C, filesBaseUrl);
}
protected void testWritePropertyValue(Type type, Object value, String expectedValue, DateTimeFormat dateTimeFormat)
throws IOException {
testWritePropertyValue(type, value, expectedValue, dateTimeFormat, null);
}
protected void testWritePropertyValue(Type type, Object value, String expectedValue, DateTimeFormat dateTimeFormat,
String filesBaseUrl) throws IOException {
// Init generator
ByteArrayOutputStream out = new ByteArrayOutputStream();
JsonGenerator jg = getFactory().createJsonGenerator(out);
// Write value
Property property = createProperty(type, value);
JSONPropertyWriter.writePropertyValue(jg, property, dateTimeFormat, filesBaseUrl);
jg.flush();
jg.close();
String result = out.toString("UTF-8");
// Assert result
assertEquals(expectedValue, result);
}
private JsonFactory getFactory() {
JsonFactoryManager jsonFactoryManager = Framework.getService(JsonFactoryManager.class);
return jsonFactoryManager.getJsonFactory();
}
private Property createProperty(Type type, Object value) {
Property property = PropertyFactory.createProperty(new DocumentPartImpl(SCHEMA),
new FieldImpl(new QName("property"), type, type), 0);
property.setValue(value);
return property;
}
}