FormatTest.java
package com.fasterxml.jackson.annotation;
import com.fasterxml.jackson.annotation.JsonFormat.Feature;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests to verify that it is possibly to merge {@link JsonFormat.Value}
* instances for overrides.
*/
public class FormatTest
{
private final JsonFormat.Value EMPTY = JsonFormat.Value.empty();
@JsonFormat(shape=JsonFormat.Shape.BOOLEAN, pattern="xyz", timezone="bogus")
private final static class Bogus { }
@Test
public void testEmptyInstanceDefaults() {
JsonFormat.Value empty = JsonFormat.Value.empty();
for (Feature f : Feature.values()) {
assertNull(empty.getFeature(f));
}
assertFalse(empty.hasLocale());
assertFalse(empty.hasPattern());
assertFalse(empty.hasShape());
assertFalse(empty.hasTimeZone());
assertFalse(empty.hasLenient());
assertFalse(empty.isLenient());
}
@Test
public void testEquality() {
assertTrue(EMPTY.equals(EMPTY));
assertTrue(new JsonFormat.Value().equals(new JsonFormat.Value()));
JsonFormat.Value v1 = JsonFormat.Value.forShape(Shape.BOOLEAN);
JsonFormat.Value v2 = JsonFormat.Value.forShape(Shape.BOOLEAN);
JsonFormat.Value v3 = JsonFormat.Value.forShape(Shape.SCALAR);
assertTrue(v1.equals(v2));
assertTrue(v2.equals(v1));
assertFalse(v1.equals(v3));
assertFalse(v3.equals(v1));
assertFalse(v2.equals(v3));
assertFalse(v3.equals(v2));
// not strictly guaranteed but...
assertFalse(v1.hashCode() == v3.hashCode());
// then let's converge
assertEquals(v1, v3.withShape(Shape.BOOLEAN));
assertFalse(v1.equals(v1.withPattern("ZBC")));
assertFalse(v1.equals(v1.withFeature(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)));
assertFalse(v1.equals(v1.withoutFeature(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)));
}
@Test
public void testToString() {
assertEquals("JsonFormat.Value(pattern=,shape=STRING,lenient=null,locale=null,timezone=null,features=EMPTY)",
JsonFormat.Value.forShape(JsonFormat.Shape.STRING).toString());
assertEquals("JsonFormat.Value(pattern=[.],shape=ANY,lenient=null,locale=null,timezone=null,features=EMPTY)",
JsonFormat.Value.forPattern("[.]").toString());
}
@Test
public void testFromAnnotation()
{
JsonFormat ann = Bogus.class.getAnnotation(JsonFormat.class);
JsonFormat.Value v = JsonFormat.Value.from(ann);
assertEquals("xyz", v.getPattern());
assertEquals(JsonFormat.Shape.BOOLEAN, v.getShape());
// note: since it's not valid, should not try access as real thing
assertEquals("bogus", v.timeZoneAsString());
// also:
assertSame(EMPTY, JsonFormat.Value.from(null));
}
@Test
public void testSimpleMerge()
{
// Start with an empty instance
assertFalse(EMPTY.hasLocale());
assertFalse(EMPTY.hasPattern());
assertFalse(EMPTY.hasShape());
assertFalse(EMPTY.hasTimeZone());
assertNull(EMPTY.getLocale());
// then with a non-empty one
final String TEST_PATTERN = "format-string"; // not parsed, usage varies
JsonFormat.Value v = JsonFormat.Value.forPattern(TEST_PATTERN);
assertTrue(v.hasPattern());
assertEquals(TEST_PATTERN, v.getPattern());
assertFalse(v.hasLocale());
assertFalse(v.hasShape());
assertFalse(v.hasTimeZone());
// and ensure nothing overridden with empty
JsonFormat.Value merged = v.withOverrides(EMPTY);
assertEquals(TEST_PATTERN, merged.getPattern());
assertFalse(merged.hasLocale());
assertFalse(merged.hasShape());
assertFalse(merged.hasTimeZone());
// minor optimization: overriding with itself has no effect
assertSame(merged, merged.withOverrides(merged));
// but that empty is overridden
merged = JsonFormat.Value.merge(EMPTY, v);
assertEquals(TEST_PATTERN, merged.getPattern());
assertFalse(merged.hasLocale());
assertFalse(merged.hasShape());
assertFalse(merged.hasTimeZone());
// also some shortcuts:
assertSame(merged, merged.withOverrides(null));
// then with some other combinations
final JsonFormat.Shape TEST_SHAPE = JsonFormat.Shape.NUMBER;
JsonFormat.Value v2 = JsonFormat.Value.forShape(TEST_SHAPE);
merged = v.withOverrides(v2);
assertEquals(TEST_PATTERN, merged.getPattern());
assertFalse(merged.hasLocale());
assertEquals(TEST_SHAPE, merged.getShape());
assertFalse(merged.hasTimeZone());
merged = v2.withOverrides(v);
assertEquals(TEST_PATTERN, merged.getPattern());
assertFalse(merged.hasLocale());
assertEquals(TEST_SHAPE, merged.getShape());
assertFalse(merged.hasTimeZone());
}
@Test
public void testMultiMerge()
{
final String TEST_PATTERN = "format-string"; // not parsed, usage varies
JsonFormat.Value format2 = JsonFormat.Value.forPattern(TEST_PATTERN);
JsonFormat.Value format3 = JsonFormat.Value.forLeniency(Boolean.FALSE);
JsonFormat.Value merged = JsonFormat.Value.mergeAll(EMPTY, format2, format3);
assertEquals(TEST_PATTERN, merged.getPattern());
assertEquals(Boolean.FALSE, merged.getLenient());
}
/*
/**********************************************************
/* Test specific value properties
/**********************************************************
*/
@Test
public void testLeniency() {
JsonFormat.Value empty = JsonFormat.Value.empty();
assertFalse(empty.hasLenient());
assertFalse(empty.isLenient());
assertNull(empty.getLenient());
JsonFormat.Value lenient = empty.withLenient(Boolean.TRUE);
assertTrue(lenient.hasLenient());
assertTrue(lenient.isLenient());
assertEquals(Boolean.TRUE, lenient.getLenient());
assertTrue(lenient.equals(lenient));
assertFalse(empty.equals(lenient));
assertFalse(lenient.equals(empty));
// should NOT create now one if no change:
assertSame(lenient, lenient.withLenient(Boolean.TRUE));
JsonFormat.Value strict = lenient.withLenient(Boolean.FALSE);
assertTrue(strict.hasLenient());
assertFalse(strict.isLenient());
assertEquals(Boolean.FALSE, strict.getLenient());
assertTrue(strict.equals(strict));
assertFalse(empty.equals(strict));
assertFalse(strict.equals(empty));
assertFalse(lenient.equals(strict));
assertFalse(strict.equals(lenient));
// and finally, can also clear up setting
JsonFormat.Value dunno = lenient.withLenient(null);
assertFalse(dunno.hasLenient());
assertFalse(dunno.isLenient());
assertNull(dunno.getLenient());
assertTrue(empty.equals(dunno));
assertTrue(dunno.equals(empty));
assertFalse(lenient.equals(dunno));
assertFalse(dunno.equals(lenient));
}
@Test
public void testCaseInsensitiveValues() {
JsonFormat.Value empty = JsonFormat.Value.empty();
assertNull(empty.getFeature(Feature.ACCEPT_CASE_INSENSITIVE_VALUES));
JsonFormat.Value insensitive = empty.withFeature(Feature.ACCEPT_CASE_INSENSITIVE_VALUES);
assertTrue(insensitive.getFeature(Feature.ACCEPT_CASE_INSENSITIVE_VALUES));
JsonFormat.Value sensitive = empty.withoutFeature(Feature.ACCEPT_CASE_INSENSITIVE_VALUES);
assertFalse(sensitive.getFeature(Feature.ACCEPT_CASE_INSENSITIVE_VALUES));
}
@Test
public void testShape() {
assertFalse(JsonFormat.Shape.STRING.isNumeric());
assertFalse(JsonFormat.Shape.STRING.isStructured());
assertTrue(JsonFormat.Shape.NUMBER_INT.isNumeric());
assertTrue(JsonFormat.Shape.NUMBER_FLOAT.isNumeric());
assertTrue(JsonFormat.Shape.NUMBER.isNumeric());
assertTrue(JsonFormat.Shape.ARRAY.isStructured());
assertTrue(JsonFormat.Shape.OBJECT.isStructured());
}
@Test
public void testFeatures() {
JsonFormat.Features f1 = JsonFormat.Features.empty();
JsonFormat.Features f2 = f1.with(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.without(Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
assertTrue(f1.equals(f1));
assertFalse(f1.equals(f2));
assertFalse(f1.equals(null));
assertFalse(f1.equals("foo"));
assertNull(f1.get(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
assertEquals(Boolean.TRUE, f2.get(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
assertNull(f1.get(Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS));
assertEquals(Boolean.FALSE, f2.get(Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS));
JsonFormat.Features f3 = f1.withOverrides(f2);
assertEquals(Boolean.TRUE, f3.get(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
assertEquals(Boolean.FALSE, f3.get(Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS));
// switch values around
JsonFormat.Features f4 = JsonFormat.Features.construct(
new Feature[] { // enabled:
Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS
}, new Feature[] { // enabled
Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY
});
assertEquals(Boolean.FALSE, f4.get(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
assertEquals(Boolean.TRUE, f4.get(Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS));
}
}