/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* This program 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, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.test.planner.entities;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.libreplan.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
import static org.libreplan.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.libreplan.business.IDataBootstrap;
import org.libreplan.business.orders.entities.HoursGroup;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderLine;
import org.libreplan.business.orders.entities.OrderLineGroup;
import org.libreplan.business.orders.entities.SchedulingDataForVersion;
import org.libreplan.business.orders.entities.TaskSource;
import org.libreplan.business.planner.entities.Dependency;
import org.libreplan.business.planner.entities.Dependency.Type;
import org.libreplan.business.planner.entities.PositionConstraintType;
import org.libreplan.business.planner.entities.Task;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.planner.entities.TaskGroup;
import org.libreplan.business.planner.entities.TaskMilestone;
import org.libreplan.business.planner.entities.TaskPositionConstraint;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE, BUSINESS_SPRING_CONFIG_TEST_FILE })
public class TaskElementTest {
@Resource
private IDataBootstrap defaultAdvanceTypesBootstrapListener;
@Before
public void loadRequiredData() {
defaultAdvanceTypesBootstrapListener.loadRequiredData();
}
private TaskElement task = new Task();
private Dependency exampleDependency;
public TaskElementTest() {
this.exampleDependency = Dependency.create(new Task(), new Task(), Type.END_START);
}
@Test
@Transactional
public void initiallyAssociatedDependenciesAreEmpty() {
assertTrue(task.getDependenciesWithThisDestination().isEmpty());
assertTrue(task.getDependenciesWithThisOrigin().isEmpty());
}
@Test(expected = UnsupportedOperationException.class)
@Transactional
public void dependenciesWithThisOriginCollectionCannotBeModified() {
task.getDependenciesWithThisOrigin().add(exampleDependency);
}
@Test(expected = UnsupportedOperationException.class)
@Transactional
public void dependenciesWithThisDestinationCollectionCannotBeModified() {
task.getDependenciesWithThisDestination().add(exampleDependency);
}
@Test
@Transactional
public void taskElementHasStartDatePropertyAndItIsRoundedToTheStartOfTheDay() {
Date now = new Date();
task.setStartDate(now);
assertThat(task.getStartDate(), equalTo(toStartOfDay(now)));
task.setEndDate(now);
assertThat(task.getEndDate(), equalTo(toStartOfDay(now)));
}
private static Date toStartOfDay(Date date) {
return LocalDate.fromDateFields(date).toDateTimeAtStartOfDay().toDate();
}
@Test
@Transactional
public void aDependencyWithThisOriginCanBeRemoved() {
Task origin = new Task();
Task destination = new Task();
Type type = Type.START_END;
Dependency.create(origin, destination, type);
assertThat(origin.getDependenciesWithThisOrigin().size(), equalTo(1));
assertThat(destination.getDependenciesWithThisDestination().size(), equalTo(1));
origin.removeDependencyWithDestination(destination, type);
assertThat(origin.getDependenciesWithThisOrigin().size(), equalTo(0));
assertThat(destination.getDependenciesWithThisDestination().size(), equalTo(0));
}
private void addDependenciesForChecking(TaskElement taskBeingTransformed, TaskElement sourceDependencyTask,
TaskElement destinationDependencyTask) {
Dependency.create(sourceDependencyTask, taskBeingTransformed, Type.END_START);
Dependency.create(taskBeingTransformed, destinationDependencyTask, Type.END_START);
}
public void detachRemovesDependenciesFromRelatedTasks() {
Task taskToDetach = TaskTest.createValidTask();
Task sourceDependencyTask = TaskTest.createValidTask();
Task destinationDependencyTask = TaskTest.createValidTask();
taskToDetach.setName("prueba");
taskToDetach.setNotes("blabla");
taskToDetach.setStartDate(new Date());
addDependenciesForChecking(taskToDetach, sourceDependencyTask, destinationDependencyTask);
taskToDetach.detach();
assertThat(sourceDependencyTask.getDependenciesWithThisOrigin().size(), equalTo(0));
assertThat(destinationDependencyTask.getDependenciesWithThisDestination().size(), equalTo(0));
}
@Test
@Transactional
public void detachRemovesTaskFromParent() {
TaskGroup parent = TaskGroupTest.createValidTaskGroup();
Task child = TaskTest.createValidTask();
Task anotherChild = TaskTest.createValidTask();
parent.addTaskElement(child);
parent.addTaskElement(anotherChild);
child.detach();
assertThat(parent.getChildren().size(), equalTo(1));
}
@Test
@Transactional
public void MilestoneOrderElementIsNull() {
TaskMilestone milestone = TaskMilestone.create(new Date());
assertThat(milestone.getOrderElement(), nullValue());
}
@Test
@Transactional
public void theDeadlineOfTheOrderElementIsCopied() {
OrderLine orderLine = OrderLine.create();
addOrderTo(orderLine);
LocalDate deadline = new LocalDate(2007, 4, 4);
orderLine.setDeadline(asDate(deadline));
TaskSource taskSource = asTaskSource(orderLine);
Task task = Task.createTask(taskSource);
assertThat(task.getDeadline(), equalTo(deadline));
}
private TaskSource asTaskSource(OrderLine orderLine) {
List<HoursGroup> hoursGroups = orderLine.getHoursGroups();
if ( hoursGroups.isEmpty() ) {
hoursGroups = Collections.singletonList(createHoursGroup(100));
}
return TaskSource.create(mockSchedulingDataForVersion(orderLine), hoursGroups);
}
public static SchedulingDataForVersion mockSchedulingDataForVersion(OrderElement orderElement) {
SchedulingDataForVersion result = createNiceMock(SchedulingDataForVersion.class);
TaskSource taskSource = createNiceMock(TaskSource.class);
expect(result.getOrderElement()).andReturn(orderElement).anyTimes();
expect(taskSource.getOrderElement()).andReturn(orderElement).anyTimes();
expect(result.getTaskSource()).andReturn(taskSource).anyTimes();
replay(result, taskSource);
return result;
}
private static Date asDate(LocalDate localDate) {
return localDate.toDateTimeAtStartOfDay().toDate();
}
private static HoursGroup createHoursGroup(int hours) {
HoursGroup result = new HoursGroup();
result.setWorkingHours(hours);
return result;
}
@Test
@Transactional
public void ifNoParentWithStartDateThePositionConstraintIsSoonAsPossible() {
OrderLine orderLine = OrderLine.create();
addOrderTo(orderLine);
TaskSource taskSource = asTaskSource(orderLine);
Task task = Task.createTask(taskSource);
assertThat(task.getPositionConstraint(), isOfType(PositionConstraintType.AS_SOON_AS_POSSIBLE));
}
private void addOrderTo(OrderElement orderElement) {
Order order = new Order();
order.useSchedulingDataFor(TaskTest.mockOrderVersion());
order.setInitDate(new Date());
order.add(orderElement);
}
@Test
@Transactional
@SuppressWarnings("unchecked")
public void ifSomeParentHasInitDateThePositionConstraintIsNotEarlierThan() {
LocalDate initDate = new LocalDate(2005, 10, 5);
OrderLineGroup group = OrderLineGroup.create();
addOrderTo(group);
group.setInitDate(asDate(initDate));
OrderLine orderLine = OrderLine.create();
group.add(orderLine);
TaskSource taskSource = asTaskSource(orderLine);
Task task = Task.createTask(taskSource);
assertThat(task.getPositionConstraint(),
allOf(isOfType(PositionConstraintType.START_NOT_EARLIER_THAN), hasValue(initDate)));
}
@Test
@Transactional
public void unlessTheOnlyParentWithInitDateNotNullIsTheOrder() {
OrderLine orderLine = OrderLine.create();
addOrderTo(orderLine);
Order order = orderLine.getOrder();
Date initDate = asDate(new LocalDate(2005, 10, 5));
order.setInitDate(initDate);
TaskSource taskSource = asTaskSource(orderLine);
Task task = Task.createTask(taskSource);
assertThat(task.getPositionConstraint(), isOfType(PositionConstraintType.AS_SOON_AS_POSSIBLE));
}
private static Matcher<TaskPositionConstraint> isOfType(final PositionConstraintType type) {
return new BaseMatcher<TaskPositionConstraint>() {
@Override
public boolean matches(Object object) {
if ( object instanceof TaskPositionConstraint ) {
TaskPositionConstraint startConstraint = (TaskPositionConstraint) object;
return startConstraint.getConstraintType() == type;
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("the start constraint must be of type " + type);
}
};
}
private static Matcher<TaskPositionConstraint> hasValue(final LocalDate value) {
return new BaseMatcher<TaskPositionConstraint>() {
@Override
public boolean matches(Object object) {
if ( object instanceof TaskPositionConstraint ) {
TaskPositionConstraint startConstraint = (TaskPositionConstraint) object;
LocalDate constraintDate = startConstraint.getConstraintDate().toDateTimeAtStartOfDay().toLocalDate();
boolean bothNotNull = value != null && constraintDate != null;
return value == constraintDate || bothNotNull && constraintDate.equals(value);
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("the start constraint must have date " + value);
}
};
}
}