/* * Copyright 2016 Google Inc. All rights reserved. * * 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. */ package org.inferred.freebuilder.processor; import static org.inferred.freebuilder.processor.util.feature.GuavaLibrary.GUAVA; import static org.inferred.freebuilder.processor.util.feature.SourceLevel.SOURCE_LEVEL; import static org.junit.Assume.assumeTrue; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.testing.EqualsTester; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.inferred.freebuilder.FreeBuilder; import org.inferred.freebuilder.processor.util.feature.FeatureSet; import org.inferred.freebuilder.processor.util.testing.BehaviorTestRunner.Shared; import org.inferred.freebuilder.processor.util.testing.BehaviorTester; import org.inferred.freebuilder.processor.util.testing.ParameterizedBehaviorTestFactory; import org.inferred.freebuilder.processor.util.testing.SourceBuilder; import org.inferred.freebuilder.processor.util.testing.TestBuilder; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.junit.runners.Parameterized.UseParametersRunnerFactory; import java.util.Arrays; import java.util.List; import java.util.stream.IntStream; import java.util.stream.Stream; import javax.tools.JavaFileObject; @RunWith(Parameterized.class) @UseParametersRunnerFactory(ParameterizedBehaviorTestFactory.class) public class SetPropertyTest { public enum TestConvention { PREFIXLESS("prefixless", "items()"), BEAN("bean", "getItems()"); private final String name; private final String getter; TestConvention(String name, String getter) { this.name = name; this.getter = getter; } public String getter() { return getter; } @Override public String toString() { return name; } } @SuppressWarnings("unchecked") @Parameters(name = "{0}<{1}>, {2}, {3}") public static Iterable<Object[]> parameters() { List<SetType> sets = Arrays.asList(SetType.values()); List<ElementFactory> elements = Arrays.asList(ElementFactory.values()); List<TestConvention> conventions = Arrays.asList(TestConvention.values()); List<FeatureSet> features = FeatureSets.ALL; return () -> Lists .cartesianProduct(sets, elements, conventions, features) .stream() .map(List::toArray) .iterator(); } @Rule public final ExpectedException thrown = ExpectedException.none(); @Shared public BehaviorTester behaviorTester; private final SetType set; private final ElementFactory elements; private final TestConvention convention; private final FeatureSet features; private final JavaFileObject setPropertyType; private final String validationErrorMessage; private final JavaFileObject validatedType; public SetPropertyTest( SetType set, ElementFactory elements, TestConvention convention, FeatureSet features) { this.set = set; this.elements = elements; this.convention = convention; this.features = features; setPropertyType = new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public abstract class DataType {") .addLine(" public abstract %s<%s> %s;", set.type(), elements.type(), convention.getter()) .addLine("") .addLine(" public static class Builder extends DataType_Builder {}") .addLine("}") .build(); validationErrorMessage = elements.errorMessage(); validatedType = new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public abstract class DataType {") .addLine(" public abstract %s<%s> %s;", set.type(), elements.type(), convention.getter()) .addLine("") .addLine(" public static class Builder extends DataType_Builder {") .addLine(" @Override public Builder addItems(%s element) {", elements.unwrappedType()) .addLine(" %s.checkArgument(%s, \"%s\");", Preconditions.class, elements.validation(), validationErrorMessage) .addLine(" return super.addItems(element);") .addLine(" }") .addLine(" }") .addLine("}") .build(); } @Test public void testDefaultEmpty() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder().build();") .addLine("assertThat(value.%s).isEmpty();", convention.getter()) .build()) .runTest(); } @Test public void testAddSingleElement() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testAddSingleElement_null() { thrown.expect(NullPointerException.class); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems((%s) null);", elements.type()) .build()) .runTest(); } @Test public void testAddSingleElement_duplicate() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.example(0)) .build()) .runTest(); } @Test public void testAddVarargs() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(1, 0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testAddVarargs_null() { assumeTrue(elements.canRepresentSingleNullElement()); thrown.expect(NullPointerException.class); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("new DataType.Builder().addItems(%s, null);", elements.example(0)) .build()) .runTest(); } @Test public void testAddVarargs_duplicate() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(0, 0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.example(0)) .build()) .runTest(); } @Test public void testAddAllIterable() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addAllItems(%s.of(%s))", ImmutableList.class, elements.examples(1, 0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testAddAllIterable_null() { thrown.expect(NullPointerException.class); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("new DataType.Builder()") .addLine(" .addAllItems(%s.asList(%s, null));", Arrays.class, elements.example(0)) .build()) .runTest(); } @Test public void testAddAllIterable_duplicate() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addAllItems(%s.of(%s))", ImmutableList.class, elements.examples(0, 0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.example(0)) .build()) .runTest(); } @Test public void testAddAllIterable_iteratesOnce() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addAllItems(new %s<>(%s))", DodgyIterable.class, elements.examples(1, 0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testAddAllStream() { assumeStreamsAvailable(); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addAllItems(Stream.of(%s))", elements.examples(1, 0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testAddAllStream_null() { assumeStreamsAvailable(); thrown.expect(NullPointerException.class); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("new DataType.Builder()") .addLine(" .addAllItems(Stream.of(%s, null));", elements.example(0)) .build()) .runTest(); } @Test public void testAddAllStream_duplicate() { assumeStreamsAvailable(); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addAllItems(Stream.of(%s))", elements.examples(0, 0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.example(0)) .build()) .runTest(); } @Test public void testAddAllIntStream() { assumeStreamsAvailable(); assumeTrue(elements == ElementFactory.INTEGERS); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addAllItems(%s.of(1, 2))", IntStream.class) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(1, 2).inOrder();", convention.getter()) .build()) .runTest(); } @Test public void testAddAllIntStream_duplicate() { assumeStreamsAvailable(); assumeTrue(elements == ElementFactory.INTEGERS); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addAllItems(%s.of(1, 1))", IntStream.class) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(1).inOrder();", convention.getter()) .build()) .runTest(); } @Test public void testRemove() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(0, 1)) .addLine(" .removeItems(%s)", elements.example(0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s);", convention.getter(), elements.example(1)) .build()) .runTest(); } @Test public void testRemove_null() { thrown.expect(NullPointerException.class); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .removeItems((%s) null);", elements.type()) .build()) .runTest(); } @Test public void testRemove_missingElement() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(1, 0)) .addLine(" .removeItems(%s)", elements.example(2)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s);", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testClear_noElements() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .clearItems()") .addLine(" .addItems(%s)", elements.examples(3, 2)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(3, 2))) .build()) .runTest(); } @Test public void testClear_twoElements() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(1, 0)) .addLine(" .clearItems()") .addLine(" .addItems(%s)", elements.examples(3, 2)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(3, 2))) .build()) .runTest(); } @Test public void testGet_returnsLiveView() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType.Builder builder = new DataType.Builder();") .addLine("%s<%s> itemsView = builder.%s;", set.type(), elements.type(), convention.getter()) .addLine("assertThat(itemsView).isEmpty();") .addLine("builder.addItems(%s);", elements.examples(1, 0)) .addLine("assertThat(itemsView).containsExactly(%s).inOrder();", elements.examples(set.inOrder(1, 0))) .addLine("builder.clearItems();") .addLine("assertThat(itemsView).isEmpty();") .addLine("builder.addItems(%s);", elements.examples(3, 2)) .addLine("assertThat(itemsView).containsExactly(%s).inOrder();", elements.examples(set.inOrder(3, 2))) .build()) .runTest(); } @Test public void testGet_returnsUnmodifiableSet() { thrown.expect(UnsupportedOperationException.class); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType.Builder builder = new DataType.Builder();") .addLine("%s<%s> itemsView = builder.%s;", set.type(), elements.type(), convention.getter()) .addLine("itemsView.add(%s);", elements.example(0)) .build()) .runTest(); } @Test public void testMergeFrom_valueInstance() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(1, 0)) .addLine(" .build();") .addLine("DataType.Builder builder = new DataType.Builder()") .addLine(" .mergeFrom(value);") .addLine("assertThat(builder.build().%s)", convention.getter()) .addLine(" .containsExactly(%s).inOrder();", elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testMergeFrom_builder() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType.Builder template = new DataType.Builder()") .addLine(" .addItems(%s);", elements.examples(1, 0)) .addLine("DataType.Builder builder = new DataType.Builder()") .addLine(" .mergeFrom(template);") .addLine("assertThat(builder.build().%s)", convention.getter()) .addLine(" .containsExactly(%s).inOrder();", elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testToBuilder_fromPartial() { behaviorTester .with(new Processor(features)) .with(new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public interface DataType {") .addLine(" %s<%s> %s;", set.type(), elements.type(), convention.getter()) .addLine("") .addLine(" Builder toBuilder();") .addLine(" class Builder extends DataType_Builder {}") .addLine("}") .build()) .with(testBuilder() .addLine("DataType value1 = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(0, 2)) .addLine(" .buildPartial();") .addLine("DataType value2 = value1.toBuilder()") .addLine(" .addItems(%s)", elements.examples(1)) .addLine(" .build();") .addLine("assertThat(value2.%s)", convention.getter()) .addLine(" .containsExactly(%s).inOrder();", elements.examples(set.inOrder(0, 2, 1))) .build()) .runTest(); } @Test public void testBuilderClear() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(1, 0)) .addLine(" .clear()") .addLine(" .addItems(%s)", elements.examples(3, 2)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(3, 2))) .build()) .runTest(); } @Test public void testBuilderClear_noBuilderFactory() { behaviorTester .with(new Processor(features)) .with(new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public abstract class DataType {") .addLine(" public abstract %s<%s> %s;", set.type(), elements.type(), convention.getter()) .addLine("") .addLine(" public static class Builder extends DataType_Builder {") .addLine(" public Builder(%s... items) {", elements.unwrappedType()) .addLine(" addItems(items);") .addLine(" }") .addLine(" }") .addLine("}") .build()) .with(testBuilder() .addLine("DataType value = new DataType.Builder(%s)", elements.example(0)) .addLine(" .clear()") .addLine(" .addItems(%s)", elements.examples(3, 2)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(3, 2))) .build()) .runTest(); } @Test public void testImmutableSetProperty() { assumeGuavaAvailable(); behaviorTester .with(new Processor(features)) .with(new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public interface DataType {") .addLine(" %s<%s> %s;", set.immutableType(), elements.type(), convention.getter()) .addLine("") .addLine(" class Builder extends DataType_Builder {}") .addLine("}") .build()) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testImmutableSetProperty_withWildcard() { assumeGuavaAvailable(); behaviorTester .with(new Processor(features)) .with(new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public interface DataType {") .addLine(" %s<? extends %s> %s;", set.immutableType(), elements.type(), convention.getter()) .addLine("") .addLine(" class Builder extends DataType_Builder {}") .addLine("}") .build()) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(0, 1)) .build()) .runTest(); } @Test public void testSetOfParameters() { // See also https://github.com/google/FreeBuilder/issues/229 behaviorTester .with(new Processor(features)) .with(new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public interface DataType<E> {") .addLine(" %s<E> %s;", set.type(), convention.getter()) .addLine("") .addLine(" class Builder<E> extends DataType_Builder<E> {}") .addLine("}") .build()) .with(testBuilder() .addLine("DataType<%1$s> value = new DataType.Builder<%1$s>()", elements.type()) .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(0, 1)) .build()) .runTest(); } @Test public void testSetOfParameterWildcards() { behaviorTester .with(new Processor(features)) .with(new SourceBuilder() .addLine("package com.example;") .addLine("@%s", FreeBuilder.class) .addLine("public interface DataType<E> {") .addLine(" %s<? extends E> %s;", set.type(), convention.getter()) .addLine("") .addLine(" class Builder<E> extends DataType_Builder<E> {}") .addLine("}") .build()) .with(testBuilder() .addLine("DataType<%1$s> value = new DataType.Builder<%1$s>()", elements.type()) .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(0, 1)) .build()) .runTest(); } @Test public void testValidation_varargsAdd() { thrown.expect(IllegalArgumentException.class); thrown.expectMessage(validationErrorMessage); behaviorTester .with(new Processor(features)) .with(validatedType) .with(testBuilder() .addLine("new DataType.Builder().addItems(%s, %s);", elements.example(0), elements.invalidExample()) .build()) .runTest(); } @Test public void testValidation_addAllStream() { assumeStreamsAvailable(); thrown.expect(IllegalArgumentException.class); thrown.expectMessage(validationErrorMessage); behaviorTester .with(new Processor(features)) .with(validatedType) .with(testBuilder() .addLine("new DataType.Builder().addAllItems(Stream.of(%s, %s));", elements.example(2), elements.invalidExample()) .build()) .runTest(); } @Test public void testValidation_addAllIterable() { thrown.expect(IllegalArgumentException.class); thrown.expectMessage(validationErrorMessage); behaviorTester .with(new Processor(features)) .with(validatedType) .with(testBuilder() .addLine("new DataType.Builder().addAllItems(%s.of(%s, %s));", ImmutableList.class, elements.example(2), elements.invalidExample()) .build()) .runTest(); } @Test public void testPrimitiveValidation_addAllIntStream() { assumeStreamsAvailable(); assumeTrue(elements == ElementFactory.INTEGERS); thrown.expect(IllegalArgumentException.class); thrown.expectMessage(validationErrorMessage); behaviorTester .with(new Processor(features)) .with(validatedType) .with(testBuilder() .addLine("new DataType.Builder().addAllItems(%s.of(3, -4));", IntStream.class) .build()) .runTest(); } @Test public void testEquality() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("new %s()", EqualsTester.class) .addLine(" .addEqualityGroup(") .addLine(" new DataType.Builder().build(),") .addLine(" new DataType.Builder().build())") .addLine(" .addEqualityGroup(") .addLine(" new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(0, 1)) .addLine(" .build(),") .addLine(" new DataType.Builder()") .addLine(" .addItems(%s)", elements.examples(0, 1)) .addLine(" .build())") .addLine(" .addEqualityGroup(") .addLine(" new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .build(),") .addLine(" new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .build())") .addLine(" .testEquals();") .build()) .runTest(); } @Test public void testJacksonInteroperability() { // See also https://github.com/google/FreeBuilder/issues/68 behaviorTester .with(new Processor(features)) .with(new SourceBuilder() .addLine("package com.example;") .addLine("import " + JsonProperty.class.getName() + ";") .addLine("@%s", FreeBuilder.class) .addLine("@%s(builder = DataType.Builder.class)", JsonDeserialize.class) .addLine("public interface DataType {") .addLine(" @JsonProperty(\"stuff\") %s<%s> %s;", set.type(), elements.type(), convention.getter()) .addLine("") .addLine(" class Builder extends DataType_Builder {}") .addLine("}") .build()) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .build();") .addLine("%1$s mapper = new %1$s();", ObjectMapper.class) .addLine("String json = mapper.writeValueAsString(value);") .addLine("DataType clone = mapper.readValue(json, DataType.class);") .addLine("assertThat(value.%s).containsExactly(%s).inOrder();", convention.getter(), elements.examples(set.inOrder(1, 0))) .build()) .runTest(); } @Test public void testFromReusesImmutableSetInstance() { assumeGuavaAvailable(); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType copy = DataType.Builder.from(value).build();") .addLine("assertThat(copy.%1$s).isSameAs(value.%1$s);", convention.getter()) .build()) .runTest(); } @Test public void testMergeFromReusesImmutableSetInstance() { assumeGuavaAvailable(); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType copy = new DataType.Builder().mergeFrom(value).build();") .addLine("assertThat(copy.%1$s).isSameAs(value.%1$s);", convention.getter()) .build()) .runTest(); } @Test public void testMergeFromEmptySetDoesNotPreventReuseOfImmutableSetInstance() { assumeGuavaAvailable(); behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType copy = new DataType.Builder()") .addLine(" .from(value)") .addLine(" .mergeFrom(new DataType.Builder())") .addLine(" .build();") .addLine("assertThat(copy.%1$s).isSameAs(value.%1$s);", convention.getter()) .build()) .runTest(); } @Test public void testModifyAndAdd() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(2)) .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .build();") .addLine("DataType copy = DataType.Builder") .addLine(" .from(value)") .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("assertThat(copy.%s)", convention.getter()) .addLine(" .containsExactly(%s)", elements.examples(set.inOrder(2, 0, 1))) .addLine(" .inOrder();") .build()) .runTest(); } @Test public void testModifyAndRemove() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType copy = DataType.Builder") .addLine(" .from(value)") .addLine(" .removeItems(%s)", elements.example(0)) .addLine(" .build();") .addLine("assertThat(copy.%s).containsExactly(%s);", convention.getter(), elements.example(1)) .build()) .runTest(); } @Test public void testModifyAndClear() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType copy = DataType.Builder") .addLine(" .from(value)") .addLine(" .clearItems()") .addLine(" .build();") .addLine("assertThat(copy.%s).isEmpty();", convention.getter()) .build()) .runTest(); } @Test public void testModifyAndClearAll() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType value = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType copy = DataType.Builder") .addLine(" .from(value)") .addLine(" .clear()") .addLine(" .build();") .addLine("assertThat(copy.%s).isEmpty();", convention.getter()) .build()) .runTest(); } @Test public void testMergeInvalidData() { thrown.expect(IllegalArgumentException.class); thrown.expectMessage(validationErrorMessage); behaviorTester .with(new Processor(features)) .with(validatedType) .with(testBuilder() .addLine("DataType value = new DataType() {") .addLine(" @Override public %s<%s> %s {", set.type(), elements.type(), convention.getter()) .addLine(" return %s.of(%s, %s);", set.immutableType(), elements.example(0), elements.invalidExample()) .addLine(" }") .addLine("};") .addLine("DataType.Builder.from(value);") .build()) .runTest(); } @Test public void testMergeCombinesSets() { behaviorTester .with(new Processor(features)) .with(setPropertyType) .with(testBuilder() .addLine("DataType data1 = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(0)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType data2 = new DataType.Builder()") .addLine(" .addItems(%s)", elements.example(2)) .addLine(" .addItems(%s)", elements.example(1)) .addLine(" .build();") .addLine("DataType copy = DataType.Builder.from(data2).mergeFrom(data1).build();") .addLine("assertThat(copy.%s)", convention.getter()) .addLine(" .containsExactly(%s)", elements.examples(set.inOrder(2, 1, 0))) .addLine(" .inOrder();") .build()) .runTest(); } private void assumeStreamsAvailable() { assumeTrue("Streams available", features.get(SOURCE_LEVEL).stream().isPresent()); } private void assumeGuavaAvailable() { assumeTrue("Guava available", features.get(GUAVA).isAvailable()); } private static TestBuilder testBuilder() { return new TestBuilder() .addImport("com.example.DataType") .addImport(Stream.class); } }