/* Copyright 2012 GanttProject Team This file is part of GanttProject, an opensource project management tool. GanttProject is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GanttProject 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 General Public License for more details. You should have received a copy of the GNU General Public License along with GanttProject. If not, see <http://www.gnu.org/licenses/>. */ package biz.ganttproject.impex.csv; import biz.ganttproject.core.model.task.TaskDefaultColumn; import com.google.common.base.Charsets; import com.google.common.base.Joiner; import com.google.common.base.Supplier; import com.google.common.collect.Maps; import junit.framework.TestCase; import net.sourceforge.ganttproject.CustomPropertyDefinition; import net.sourceforge.ganttproject.TestSetupHelper; import net.sourceforge.ganttproject.TestSetupHelper.TaskManagerBuilder; import net.sourceforge.ganttproject.language.GanttLanguage; import net.sourceforge.ganttproject.resource.HumanResource; import net.sourceforge.ganttproject.resource.HumanResourceManager; import net.sourceforge.ganttproject.roles.RoleManager; import net.sourceforge.ganttproject.roles.RoleManagerImpl; import net.sourceforge.ganttproject.task.Task; import net.sourceforge.ganttproject.task.TaskContainmentHierarchyFacade; import net.sourceforge.ganttproject.task.TaskManager; import net.sourceforge.ganttproject.task.dependency.TaskDependency; import net.sourceforge.ganttproject.util.collect.Pair; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Stream; import static biz.ganttproject.impex.csv.SpreadsheetFormat.CSV; import static biz.ganttproject.impex.csv.SpreadsheetFormat.XLS; /** * Tests spreadsheet (CSV and XLS) import with GP semantics. * * @author dbarashev (Dmitry Barashev) */ public class GPCsvImportTest extends TestCase { private Supplier<InputStream> createSupplier(final byte[] data) { return () -> new ByteArrayInputStream(data); } private static Map<String, Task> buildTaskMap(TaskManager taskManager) { return Maps.uniqueIndex(Arrays.asList(taskManager.getTasks()), Task::getName); } private Map<String, HumanResource> buildResourceMap(HumanResourceManager resourceManager) { return Maps.uniqueIndex(resourceManager.getResources(), HumanResource::getName); } private static void assertDependency(Task dependant, Task dependee) { for (TaskDependency dep : dependant.getDependenciesAsDependant().toArray()) { if (dep.getDependee() == dependee) { return; } } fail("Can't find " + dependee + " in the list of predecessors of " + dependant); } private static void assertDependency(Task dependant, Task dependee, int lag) { for (TaskDependency dep : dependant.getDependenciesAsDependant().toArray()) { if (dep.getDependee() == dependee) { assertEquals("Unexpected lag value", lag, dep.getDifference()); return; } } fail("Can't find " + dependee + " in the list of predecessors of " + dependant); } @Override protected void setUp() throws Exception { TaskDefaultColumn.setLocaleApi(new TaskDefaultColumn.LocaleApi() { @Override public String i18n(String key) { return GanttLanguage.getInstance().getText(key); } }); GanttLanguage.getInstance().setShortDateFormat(new SimpleDateFormat("dd/MM/yy")); } public void testImportAssignments() throws Exception { String header1 = buildTaskHeader( TaskRecords.TaskFields.NAME, TaskRecords.TaskFields.BEGIN_DATE, TaskRecords.TaskFields.END_DATE, TaskRecords.TaskFields.RESOURCES, TaskRecords.TaskFields.DURATION, TaskRecords.TaskFields.COMPLETION, TaskRecords.TaskFields.WEB_LINK, TaskRecords.TaskFields.NOTES, TaskRecords.TaskFields.PREDECESSORS, TaskRecords.TaskFields.ID); String data1 = "t1,23/07/12,25/07/12,Joe;John,,,,,,"; String header2 = buildResourceHeader(ResourceRecords.ResourceFields.NAME, ResourceRecords.ResourceFields.ID, ResourceRecords.ResourceFields.ROLE); String data2 = "Joe,1,,,\nJohn,2,,,\nJack,3,,,"; for (Pair<SpreadsheetFormat, Supplier<InputStream>> pair : createPairs(header1, data1, "", header2, data2)) { TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder(); HumanResourceManager resourceManager = builder.getResourceManager(); Map<String, Task> taskMap = doTestImportAssignments(pair.second(), pair.first(), builder, null, resourceManager, new RoleManagerImpl()); Task t1 = taskMap.get("t1"); assertNotNull(t1); Map<String, HumanResource> resourceMap = buildResourceMap(resourceManager); assertNotNull(t1.getAssignmentCollection().getAssignment(resourceMap.get("Joe"))); assertNotNull(t1.getAssignmentCollection().getAssignment(resourceMap.get("John"))); } } public void testImportResourceRole() throws Exception { String header1 = buildTaskHeader( TaskRecords.TaskFields.NAME, TaskRecords.TaskFields.BEGIN_DATE, TaskRecords.TaskFields.END_DATE, TaskRecords.TaskFields.RESOURCES, TaskRecords.TaskFields.DURATION, TaskRecords.TaskFields.COMPLETION, TaskRecords.TaskFields.WEB_LINK, TaskRecords.TaskFields.NOTES, TaskRecords.TaskFields.PREDECESSORS, TaskRecords.TaskFields.ID); String data1 = ""; String header2 = buildResourceHeader(ResourceRecords.ResourceFields.NAME, ResourceRecords.ResourceFields.ID, ResourceRecords.ResourceFields.ROLE); String data2 = "Joe,1,Default:1"; for (Pair<SpreadsheetFormat, Supplier<InputStream>> pair : createPairs(header1, data1, "", header2, data2)) { TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder(); HumanResourceManager resourceManager = builder.getResourceManager(); doTestImportAssignments(pair.second(), pair.first(), builder, null, resourceManager, new RoleManagerImpl()); Map<String, HumanResource> resourceMap = buildResourceMap(resourceManager); assertEquals("project manager", resourceMap.get("Joe").getRole().getName()); } } public void testCustomFields() throws Exception { String header1 = "Field1," + buildTaskHeader(TaskRecords.TaskFields.ID, TaskRecords.TaskFields.NAME, TaskRecords.TaskFields.BEGIN_DATE, TaskRecords.TaskFields.END_DATE, TaskRecords.TaskFields.PREDECESSORS, TaskRecords.TaskFields.RESOURCES, TaskRecords.TaskFields.DURATION, TaskRecords.TaskFields.COMPLETION, TaskRecords.TaskFields.WEB_LINK, TaskRecords.TaskFields.NOTES) + ",Field2"; String data1 = "value1,,t1,23/07/12,25/07/12,,,,,,,value2"; for (Pair<SpreadsheetFormat, Supplier<InputStream>> pair : createPairs(header1, data1)) { TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder(); TaskManager taskManager = builder.build(); Map<String, Task> taskMap = doTestImportAssignments(pair.second(), pair.first(), builder, taskManager, null, null); Task t1 = taskMap.get("t1"); assertNotNull(t1); CustomPropertyDefinition def1 = taskManager.getCustomPropertyManager().getCustomPropertyDefinition("Field1"); CustomPropertyDefinition def2 = taskManager.getCustomPropertyManager().getCustomPropertyDefinition("Field2"); assertNotNull(def1); assertNotNull(def2); assertEquals("value1", t1.getCustomValues().getValue(def1)); assertEquals("value2", t1.getCustomValues().getValue(def2)); } } private String buildTaskHeader(TaskRecords.TaskFields... taskFields) { return Joiner.on(',').join(Stream.of(taskFields).map(TaskRecords.TaskFields::toString).iterator()); } private String buildResourceHeader(ResourceRecords.ResourceFields... resourceFields) { return Joiner.on(',').join(Stream.of(resourceFields).map(ResourceRecords.ResourceFields::toString).iterator()); } public void testDependencies() throws Exception { String header1 = buildTaskHeader( TaskRecords.TaskFields.ID, TaskRecords.TaskFields.NAME, TaskRecords.TaskFields.BEGIN_DATE, TaskRecords.TaskFields.END_DATE, TaskRecords.TaskFields.RESOURCES, TaskRecords.TaskFields.DURATION, TaskRecords.TaskFields.COMPLETION, TaskRecords.TaskFields.WEB_LINK, TaskRecords.TaskFields.NOTES, TaskRecords.TaskFields.PREDECESSORS); String data1 = "1,t1,23/07/12,25/07/12,,,,,,"; String data2 = "2,t2,26/07/12,27/07/12,,,,,,1"; String data3 = "3,t3,26/07/12,30/07/12,,,,,,1"; String data4 = "4,t4,26/07/12,30/07/12,,,,,,1-FS=P1D"; String data5 = "5,t5,26/07/12,30/07/12,,,,,,1-FS=P-1D"; for (Pair<SpreadsheetFormat, Supplier<InputStream>> pair : createPairs(header1, data1, data2, data3, data4, data5)) { TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder(); Map<String, Task> taskMap = doTestImportAssignments(pair.second(), pair.first(), builder, null, null, null); Task t1 = taskMap.get("t1"); Task t2 = taskMap.get("t2"); Task t3 = taskMap.get("t3"); Task t4 = taskMap.get("t4"); Task t5 = taskMap.get("t5"); assertDependency(t2, t1); assertDependency(t3, t1); assertDependency(t4, t1, 1); assertDependency(t5, t1, -1); } } public void testMilestone() throws Exception { String header1 = buildTaskHeader( TaskRecords.TaskFields.ID, TaskRecords.TaskFields.NAME, TaskRecords.TaskFields.BEGIN_DATE, TaskRecords.TaskFields.END_DATE, TaskRecords.TaskFields.DURATION, TaskRecords.TaskFields.RESOURCES, TaskRecords.TaskFields.COMPLETION, TaskRecords.TaskFields.WEB_LINK, TaskRecords.TaskFields.NOTES, TaskRecords.TaskFields.PREDECESSORS); String data1 = "1,t1,23/07/12,24/07/12,1,,,,,"; String data2 = "2,t2,26/07/12,26/07/12,0,,,,,"; for (Pair<SpreadsheetFormat, Supplier<InputStream>> pair : createPairs(header1, data1, data2)) { TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder(); Map<String, Task> taskMap = doTestImportAssignments(pair.second(), pair.first(), builder, null, null, null); Task t1 = taskMap.get("t1"); Task t2 = taskMap.get("t2"); assertFalse(t1.isMilestone()); assertTrue(t2.isMilestone()); } } public void testHierarchy() throws Exception { String header1 = buildTaskHeader( TaskRecords.TaskFields.ID, TaskRecords.TaskFields.NAME, TaskRecords.TaskFields.BEGIN_DATE, TaskRecords.TaskFields.END_DATE, TaskRecords.TaskFields.DURATION, TaskRecords.TaskFields.OUTLINE_NUMBER); String data1 = "1,t1,23/07/12,26/07/12,1,1"; String data2 = "2,t2,23/07/12,24/07/12,1,1.1"; String data3 = "3,t3,24/07/12,26/07/12,1,1.2"; String data4 = "4,t4,24/07/12,25/07/12,1,1.2.1"; String data5 = "5,t5,25/07/12,26/07/12,1,1.2.2"; for (Pair<SpreadsheetFormat, Supplier<InputStream>> pair : createPairs(header1, data1, data2, data3, data4, data5)) { TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder(); TaskManager taskManager = builder.build(); Map<String, Task> taskMap = doTestImportAssignments(pair.second(), pair.first(), builder, taskManager, null, null); TaskContainmentHierarchyFacade hierarchy = taskManager.getTaskHierarchy(); Task t1 = taskMap.get("t1"); Task t2 = taskMap.get("t2"); Task t3 = taskMap.get("t3"); Task t4 = taskMap.get("t4"); Task t5 = taskMap.get("t5"); assertEquals(t3, hierarchy.getContainer(t5)); assertEquals(t3, hierarchy.getContainer(t4)); assertEquals(t1, hierarchy.getContainer(t3)); assertEquals(t1, hierarchy.getContainer(t2)); } } public void testUseEndDateInsteadOfDuration() throws Exception { String header1 = buildTaskHeader( TaskRecords.TaskFields.ID, TaskRecords.TaskFields.NAME, TaskRecords.TaskFields.BEGIN_DATE, TaskRecords.TaskFields.END_DATE); String data1 = "1,t1,23/07/12,26/07/12"; for (Pair<SpreadsheetFormat, Supplier<InputStream>> pair : createPairs(header1, data1)) { TaskManagerBuilder builder = TestSetupHelper.newTaskManagerBuilder(); Map<String, Task> taskMap = doTestImportAssignments(pair.second(), pair.first(), builder, null, null, null); assertEquals(4.0f, taskMap.get("t1").getDuration().getLength(builder.getTimeUnitStack().getDefaultTimeUnit())); } } private static void assertOrder(String first, String second) { assertEquals(-1, TaskRecords.OUTLINE_NUMBER_COMPARATOR.compare(first, second)); assertEquals(1, TaskRecords.OUTLINE_NUMBER_COMPARATOR.compare(second, first)); assertEquals(0, TaskRecords.OUTLINE_NUMBER_COMPARATOR.compare(first, first)); assertEquals(0, TaskRecords.OUTLINE_NUMBER_COMPARATOR.compare(second, second)); } public void testOutlineNumberComparator() { assertOrder("1", "2"); assertOrder("1", "1.1"); assertOrder("1.1", "1.2"); assertOrder("1.1", "2"); assertOrder("1.2", "1.10"); assertOrder("2", "10"); } private List<Pair<SpreadsheetFormat, Supplier<InputStream>>> createPairs(String... data) throws Exception { List<Pair<SpreadsheetFormat, Supplier<InputStream>>> pairs = new ArrayList<>(); pairs.add(Pair.create(CSV, createSupplier(Joiner.on('\n').join(data).getBytes(Charsets.UTF_8)))); pairs.add(Pair.create(XLS, createSupplier(createXls(data)))); return pairs; } private Map<String, Task> doTestImportAssignments(Supplier<InputStream> supplier, SpreadsheetFormat format, TaskManagerBuilder builder, TaskManager taskManager, HumanResourceManager resourceManager, RoleManager roleManager) throws IOException { if (taskManager == null) { taskManager = builder.build(); } GanttCSVOpen importer = new GanttCSVOpen(supplier, format, taskManager, resourceManager, roleManager, builder.getTimeUnitStack()); importer.load(); return buildTaskMap(taskManager); } private byte[] createXls(String... rows) throws Exception { ByteArrayOutputStream stream = new ByteArrayOutputStream(); try (SpreadsheetWriter writer = new XlsWriterImpl(stream)) { for (String row : rows) { for (String line : row.split("\n", -1)) { for (String cell : line.split(",", -1)) { writer.print(cell.trim()); } writer.println(); } } } return stream.toByteArray(); } }