/**
* ***************************************************************************
* Copyright (c) 2010 Qcadoo Limited
* Project: Qcadoo MES
* Version: 1.4
*
* This file is part of Qcadoo.
*
* Qcadoo is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* ***************************************************************************
*/
package com.qcadoo.mes.technologies.tree.builder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.test.util.ReflectionTestUtils;
import com.google.common.collect.Lists;
import com.qcadoo.mes.basic.constants.BasicConstants;
import com.qcadoo.mes.technologies.constants.OperationProductInComponentFields;
import com.qcadoo.mes.technologies.constants.TechnologiesConstants;
import com.qcadoo.mes.technologies.constants.TechnologyOperationComponentFields;
import com.qcadoo.mes.technologies.constants.TechnologyOperationComponentType;
import com.qcadoo.mes.technologies.tree.builder.api.InternalOperationProductComponent;
import com.qcadoo.mes.technologies.tree.builder.api.InternalTechnologyOperationComponent;
import com.qcadoo.mes.technologies.tree.builder.api.ItemWithQuantity;
import com.qcadoo.mes.technologies.tree.builder.api.OperationProductComponent;
import com.qcadoo.mes.technologies.tree.builder.api.OperationProductComponent.OperationCompType;
import com.qcadoo.mes.technologies.tree.builder.api.TechnologyOperationComponent;
import com.qcadoo.mes.technologies.tree.builder.api.TechnologyTreeAdapter;
import com.qcadoo.model.api.DataDefinition;
import com.qcadoo.model.api.Entity;
import com.qcadoo.model.api.EntityTree;
import com.qcadoo.model.api.EntityTreeNode;
import com.qcadoo.model.api.NumberService;
public class TechnologyTreeBuildServiceImplTest {
private TechnologyTreeBuildServiceImpl treeBuildService;
@Mock
private TechnologyTreeComponentsFactory componentsFactory;
@Mock
private Entity toc2op, toc2opic1prod, toc2opoc1prod;
@Mock
private Entity toc1op, toc1opic1prod, toc1opoc1prod;
@Mock
private NumberService numberService;
@Captor
private ArgumentCaptor<Collection<Entity>> toc1opicCaptor, toc1opocCaptor, toc2opicCaptor, toc2opocCaptor,
toc1childrenCaptor, toc2childrenCaptor;
@Before
public final void init() {
MockitoAnnotations.initMocks(this);
treeBuildService = new TechnologyTreeBuildServiceImpl();
given(componentsFactory.buildToc()).willAnswer(new Answer<InternalTechnologyOperationComponent>() {
@Override
public InternalTechnologyOperationComponent answer(final InvocationOnMock invocation) throws Throwable {
return buildToc();
}
});
given(componentsFactory.buildOpc(Mockito.any(OperationCompType.class))).willAnswer(
new Answer<InternalOperationProductComponent>() {
@Override
public InternalOperationProductComponent answer(final InvocationOnMock invocation) throws Throwable {
return buildOpc((OperationCompType) invocation.getArguments()[0]);
}
});
ReflectionTestUtils.setField(treeBuildService, "componentsFactory", componentsFactory);
ReflectionTestUtils.setField(treeBuildService, "numberService", numberService);
}
private InternalOperationProductComponent buildOpc(final OperationCompType type) {
DataDefinition dataDef = mock(DataDefinition.class);
given(dataDef.getPluginIdentifier()).willReturn(TechnologiesConstants.PLUGIN_IDENTIFIER);
given(dataDef.getName()).willReturn(type.getModelName());
Entity wrappedEntity = mock(Entity.class);
given(dataDef.create()).willReturn(wrappedEntity);
given(wrappedEntity.copy()).willReturn(wrappedEntity);
return new OperationProductComponentImpl(type, dataDef);
}
private InternalTechnologyOperationComponent buildToc() {
DataDefinition dataDef = mock(DataDefinition.class);
given(dataDef.getPluginIdentifier()).willReturn(TechnologiesConstants.PLUGIN_IDENTIFIER);
given(dataDef.getName()).willReturn(TechnologiesConstants.MODEL_TECHNOLOGY_OPERATION_COMPONENT);
Entity wrappedEntity = mock(Entity.class);
given(dataDef.create()).willReturn(wrappedEntity);
given(wrappedEntity.copy()).willReturn(wrappedEntity);
return new TechnologyOperationCompImpl(dataDef);
}
private class TestTreeAdapter implements TechnologyTreeAdapter<TocHolder, ProductHolder> {
@Override
public void setOpCompCustomFields(final TechnologyOperationComponent toc, final TocHolder from) {
}
@Override
public void setOpProductCompCustomFields(final OperationProductComponent opc, final ProductHolder from) {
}
@Override
public Collection<ItemWithQuantity<ProductHolder>> extractInputProducts(final TocHolder from) {
return from.getInputs();
}
@Override
public Collection<ItemWithQuantity<ProductHolder>> extractOutputProducts(final TocHolder from) {
return from.getOutputs();
}
@Override
public Iterable<TocHolder> extractSubOperations(final TocHolder from) {
return from.getSubOps();
}
@Override
public Entity buildProductEntity(final ProductHolder from) {
return from.getProduct();
}
@Override
public Entity buildOperationEntity(final TocHolder from) {
return from.getOperation();
}
}
private interface TocHolder {
Collection<ItemWithQuantity<ProductHolder>> getInputs();
Collection<ItemWithQuantity<ProductHolder>> getOutputs();
Entity getOperation();
Iterable<TocHolder> getSubOps();
}
private interface ProductHolder {
Entity getProduct();
}
private TocHolder mockCustomTreeRepresentation() {
DataDefinition toc2opDataDef = mockOperationDataDef();
given(toc2op.getDataDefinition()).willReturn(toc2opDataDef);
DataDefinition toc1opDataDef = mockOperationDataDef();
given(toc1op.getDataDefinition()).willReturn(toc1opDataDef);
ItemWithQuantity<ProductHolder> toc2input1 = mockProduct(toc2opic1prod, BigDecimal.ONE);
Collection<ItemWithQuantity<ProductHolder>> toc2inputs = Lists.newArrayList();
toc2inputs.add(toc2input1);
ItemWithQuantity<ProductHolder> toc2output1 = mockProduct(toc2opoc1prod, BigDecimal.ONE);
Collection<ItemWithQuantity<ProductHolder>> toc2outputs = Lists.newArrayList();
toc2outputs.add(toc2output1);
TocHolder toc2 = mockTocNode(toc2op, toc2inputs, toc2outputs, Collections.<TocHolder> emptyList());
ItemWithQuantity<ProductHolder> toc1input1 = mockProduct(toc1opic1prod, BigDecimal.ONE);
Collection<ItemWithQuantity<ProductHolder>> toc1inputs = Lists.newArrayList();
toc1inputs.add(toc1input1);
ItemWithQuantity<ProductHolder> toc1output1 = mockProduct(toc1opoc1prod, BigDecimal.ONE);
Collection<ItemWithQuantity<ProductHolder>> toc1outputs = Lists.newArrayList();
toc1outputs.add(toc1output1);
return mockTocNode(toc1op, toc1inputs, toc1outputs, Lists.newArrayList(toc2));
}
private ItemWithQuantity<ProductHolder> mockProduct(final Entity productEntity, final BigDecimal quantity) {
ProductHolder product = mock(ProductHolder.class);
given(product.getProduct()).willReturn(productEntity);
given(numberService.setScale(quantity)).willReturn(quantity);
DataDefinition dataDef = mockProductDataDef();
given(productEntity.getDataDefinition()).willReturn(dataDef);
return new ItemWithQuantity<ProductHolder>(product, quantity, 0);
}
private DataDefinition mockOperationDataDef() {
return mockDataDefinition(TechnologiesConstants.PLUGIN_IDENTIFIER, TechnologiesConstants.MODEL_OPERATION);
}
private DataDefinition mockProductDataDef() {
return mockDataDefinition(BasicConstants.PLUGIN_IDENTIFIER, BasicConstants.MODEL_PRODUCT);
}
private DataDefinition mockDataDefinition(final String pluginId, final String modelName) {
DataDefinition dataDefinition = mock(DataDefinition.class);
given(dataDefinition.getPluginIdentifier()).willReturn(pluginId);
given(dataDefinition.getName()).willReturn(modelName);
return dataDefinition;
}
private TocHolder mockTocNode(final Entity operation, final Collection<ItemWithQuantity<ProductHolder>> inputs,
final Collection<ItemWithQuantity<ProductHolder>> outputs, final Iterable<TocHolder> subOps) {
TocHolder tocNode = mock(TocHolder.class);
given(tocNode.getOperation()).willReturn(operation);
given(tocNode.getInputs()).willReturn(inputs);
given(tocNode.getOutputs()).willReturn(outputs);
given(tocNode.getSubOps()).willReturn(subOps);
return tocNode;
}
@Test
public final void shouldBuildTree() {
// given
TocHolder customTreeRoot = mockCustomTreeRepresentation();
// when
EntityTree tree = treeBuildService.build(customTreeRoot, new TestTreeAdapter());
// then
EntityTreeNode root = tree.getRoot();
assertNotNull(root);
Entity toc1 = extractEntity(root);
verify(toc1).setField(TechnologyOperationComponentFields.ENTITY_TYPE,
TechnologyOperationComponentType.OPERATION.getStringValue());
verify(toc1).setField(TechnologyOperationComponentFields.OPERATION, toc1op);
verify(toc1).setField(Mockito.eq(TechnologyOperationComponentFields.OPERATION_PRODUCT_IN_COMPONENTS),
toc1opicCaptor.capture());
Collection<Entity> toc1opics = toc1opicCaptor.getValue();
assertEquals(1, toc1opics.size());
Entity toc1opic = toc1opics.iterator().next();
verify(toc1opic).setField(OperationProductInComponentFields.QUANTITY, BigDecimal.ONE);
verify(toc1opic).setField(OperationProductInComponentFields.PRODUCT, toc1opic1prod);
verify(toc1).setField(Mockito.eq(TechnologyOperationComponentFields.OPERATION_PRODUCT_OUT_COMPONENTS),
toc1opocCaptor.capture());
Collection<Entity> toc1opocs = toc1opocCaptor.getValue();
assertEquals(1, toc1opocs.size());
Entity toc1opoc = toc1opocs.iterator().next();
verify(toc1opoc).setField(OperationProductInComponentFields.QUANTITY, BigDecimal.ONE);
verify(toc1opoc).setField(OperationProductInComponentFields.PRODUCT, toc1opoc1prod);
verify(toc1).setField(Mockito.eq(TechnologyOperationComponentFields.CHILDREN), toc1childrenCaptor.capture());
Collection<Entity> toc1children = toc1childrenCaptor.getValue();
assertEquals(1, toc1children.size());
Entity toc2 = toc1children.iterator().next();
verify(toc2).setField(TechnologyOperationComponentFields.ENTITY_TYPE,
TechnologyOperationComponentType.OPERATION.getStringValue());
verify(toc2).setField(TechnologyOperationComponentFields.OPERATION, toc2op);
verify(toc2).setField(Mockito.eq(TechnologyOperationComponentFields.OPERATION_PRODUCT_IN_COMPONENTS),
toc2opicCaptor.capture());
Collection<Entity> toc2opics = toc2opicCaptor.getValue();
assertEquals(1, toc2opics.size());
Entity toc2opic = toc2opics.iterator().next();
verify(toc2opic).setField(OperationProductInComponentFields.QUANTITY, BigDecimal.ONE);
verify(toc2opic).setField(OperationProductInComponentFields.PRODUCT, toc2opic1prod);
verify(toc2).setField(Mockito.eq(TechnologyOperationComponentFields.OPERATION_PRODUCT_OUT_COMPONENTS),
toc2opocCaptor.capture());
Collection<Entity> toc2opocs = toc2opocCaptor.getValue();
assertEquals(1, toc2opocs.size());
Entity toc2opoc = toc2opocs.iterator().next();
verify(toc2opoc).setField(OperationProductInComponentFields.QUANTITY, BigDecimal.ONE);
verify(toc2opoc).setField(OperationProductInComponentFields.PRODUCT, toc2opoc1prod);
verify(toc2).setField(Mockito.eq(TechnologyOperationComponentFields.CHILDREN), toc2childrenCaptor.capture());
Collection<Entity> toc2children = toc2childrenCaptor.getValue();
assertTrue(toc2children.isEmpty());
}
private Entity extractEntity(final Entity wrapper) {
return (Entity) ReflectionTestUtils.getField(wrapper, "entity");
}
}