package com.fasterxml.jackson.annotation; import com.fasterxml.jackson.annotation.JsonFormat.Feature; import com.fasterxml.jackson.annotation.JsonFormat.Shape; /** * Tests to verify that it is possibly to merge {@link JsonFormat.Value} * instances for overrides. */ public class FormatTest extends TestBase { private final JsonFormat.Value EMPTY = JsonFormat.Value.empty(); @JsonFormat(shape=JsonFormat.Shape.BOOLEAN, pattern="xyz", timezone="bogus") private final static class Bogus { } 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()); } 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))); } 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()); } 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)); } 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()); } 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 /********************************************************** */ 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)); } 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)); } 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()); } 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)); } }