/*
* Copyright 2014 Daniel Bechler
*
* 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 de.danielbechler.diff.differ;
import de.danielbechler.diff.access.Instances;
import de.danielbechler.diff.access.TypeAwareAccessor;
import de.danielbechler.diff.comparison.PrimitiveDefaultValueMode;
import de.danielbechler.diff.comparison.PrimitiveDefaultValueModeResolver;
import de.danielbechler.diff.node.DiffNode;
import de.danielbechler.diff.selector.BeanPropertyElementSelector;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
import static de.danielbechler.diff.comparison.PrimitiveDefaultValueMode.ASSIGNED;
import static de.danielbechler.diff.comparison.PrimitiveDefaultValueMode.UNASSIGNED;
import static de.danielbechler.diff.helper.MockitoAnswers.withType;
import static de.danielbechler.diff.helper.MockitoExtensions.returnClass;
import static de.danielbechler.diff.helper.NodeAssertions.assertThat;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
/**
* @author Daniel Bechler
*/
public class PrimitiveDifferTest
{
private PrimitiveDiffer primitiveDiffer;
@Mock
private DifferDispatcher differDispatcher;
@Mock
private TypeAwareAccessor accessor;
@Mock
private PrimitiveDefaultValueModeResolver primitiveDefaultValueModeResolver;
@Mock
private Instances instances;
private static <T> Object[] instances(final Class<T> type, final T base, final T working, final T fresh)
{
return new Object[]{type, base, working, fresh};
}
@BeforeMethod
public void setUp()
{
initMocks(this);
}
private void given_primitiveDiffer_with_defaultValueMode(final PrimitiveDefaultValueMode mode)
{
when(primitiveDefaultValueModeResolver.resolvePrimitiveDefaultValueMode(any(DiffNode.class))).thenReturn(mode);
primitiveDiffer = new PrimitiveDiffer(primitiveDefaultValueModeResolver);
}
@Test(dataProvider = "removals")
public void testRemovedWhenPrimitiveDefaultModeIsUnassigned(final Class<?> type,
final Object base,
final Object working,
final Object fresh) throws Exception
{
given_primitiveDiffer_with_defaultValueMode(UNASSIGNED);
given_instances(type, base, working, fresh);
when(instances.hasBeenRemoved()).thenReturn(true);
final DiffNode node = primitiveDiffer.compare(DiffNode.ROOT, instances);
assertThat(node).self().hasState(DiffNode.State.REMOVED);
}
@Test(dataProvider = "changes")
public void testChangedWhenPrimitiveDefaultModeIsUnassigned(final Class<?> type,
final Object base,
final Object working,
final Object fresh) throws Exception
{
given_primitiveDiffer_with_defaultValueMode(UNASSIGNED);
given_instances(type, base, working, fresh);
final DiffNode node = primitiveDiffer.compare(DiffNode.ROOT, instances);
assertThat(node).self().hasState(DiffNode.State.CHANGED);
}
@Test(dataProvider = "additions")
public void testAddedWhenPrimitiveDefaultModeIsUnassigned(final Class<?> type,
final Object base,
final Object working,
final Object fresh) throws Exception
{
given_primitiveDiffer_with_defaultValueMode(UNASSIGNED);
given_instances(type, base, working, fresh);
when(instances.hasBeenAdded()).thenReturn(true);
final DiffNode node = primitiveDiffer.compare(DiffNode.ROOT, instances);
assertThat(node).self().hasState(DiffNode.State.ADDED);
}
@Test(dataProvider = "changesWhenDefaultModeIsAssigned")
public void testChangedWhenPrimitiveDefaultModeIsAssigned(final Class<?> type,
final Object base,
final Object working,
final Object fresh) throws Exception
{
given_primitiveDiffer_with_defaultValueMode(ASSIGNED);
given_instances(type, base, working, fresh);
final DiffNode node = primitiveDiffer.compare(DiffNode.ROOT, instances);
assertThat(node).self().hasState(DiffNode.State.CHANGED);
}
@Test(dataProvider = "wrapperTypes", expectedExceptions = IllegalArgumentException.class)
public void testThrowsIllegalArgumentExceptionWhenNonPrimitiveTypeIsPassed(final Class<?> wrapperType) throws Exception
{
given_primitiveDiffer_with_defaultValueMode(UNASSIGNED);
instances = mock(Instances.class);
when(instances.getType()).thenAnswer(new Answer<Object>()
{
public Object answer(final InvocationOnMock invocation) throws Throwable
{
return String.class;
}
});
// when(accessor.getType()).then(returnClass(wrapperType));
primitiveDiffer.compare(DiffNode.ROOT, instances);
}
private Instances given_instances(final Class<?> type,
final Object base,
final Object working,
final Object fresh)
{
when(accessor.getType()).then(returnClass(type));
when(accessor.getElementSelector()).thenReturn(new BeanPropertyElementSelector("ignored"));
instances = mock(Instances.class);
when(instances.getWorking()).thenReturn(working);
when(instances.getBase()).thenReturn(base);
when(instances.getFresh()).thenReturn(fresh);
when(instances.getSourceAccessor()).thenReturn(accessor);
when(instances.getType()).thenAnswer(withType(type));
return instances;
}
@DataProvider
public Object[][] additions()
{
return new Object[][]{
instances(int.class, 0, 1, 0),
instances(long.class, 0L, 1L, 0L),
instances(float.class, 0F, 1F, 0F),
instances(double.class, 0D, 1D, 0D),
instances(boolean.class, false, true, false),
};
}
@DataProvider
public Object[][] removals()
{
return new Object[][]{
instances(int.class, 1, 0, 0),
instances(long.class, 1L, 0L, 0L),
instances(float.class, 1F, 0F, 0F),
instances(double.class, 1D, 0D, 0D),
instances(boolean.class, true, false, false),
};
}
@DataProvider
public Object[][] changes()
{
return new Object[][]{
instances(int.class, 1, 2, 0),
instances(long.class, 1L, 2L, 0L),
instances(float.class, 1F, 2F, 0F),
instances(double.class, 1D, 2D, 0D),
};
}
@DataProvider
public Object[][] wrapperTypes()
{
return new Object[][]{
new Object[]{Integer.class},
new Object[]{Long.class},
new Object[]{Float.class},
new Object[]{Double.class},
new Object[]{Short.class},
new Object[]{Byte.class},
new Object[]{Boolean.class},
};
}
@DataProvider
public Object[][] changesWhenDefaultModeIsAssigned()
{
final List<Object[]> objects = new ArrayList<Object[]>();
objects.addAll(asList(additions()));
objects.addAll(asList(changes()));
objects.addAll(asList(removals()));
//noinspection ToArrayCallWithZeroLengthArrayArgument
return objects.toArray(new Object[0][0]);
}
}