/******************************************************************************* * Copyright (c) 2012 Arapiki Solutions Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * psmith - initial API and * implementation and/or initial documentation *******************************************************************************/ package com.buildml.refactor; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.List; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.buildml.model.CommonTestUtils; import com.buildml.model.FatalBuildStoreError; import com.buildml.model.IActionMgr; import com.buildml.model.IActionMgr.OperationType; import com.buildml.model.IBuildStore; import com.buildml.model.IFileGroupMgr; import com.buildml.model.IFileMgr; import com.buildml.model.IPackageMemberMgr; import com.buildml.model.IPackageRootMgr; import com.buildml.model.IPackageMemberMgr.*; import com.buildml.model.undo.MultiUndoOp; import com.buildml.model.IPackageMgr; import com.buildml.refactor.CanNotRefactorException.Cause; import com.buildml.refactor.imports.ImportRefactorer; import com.buildml.utils.errors.ErrorCode; /** * Test cases to verify the IImportRefactorer implementation. These tests focus * on moving members to other packages. * * @author Peter Smith <psmith@arapiki.com> */ public class TestImportRefactorMoveToPackage { /*=====================================================================================* * FIELDS/TYPES *=====================================================================================*/ private IBuildStore buildStore; private IFileMgr fileMgr; private IActionMgr actionMgr; private IPackageMgr pkgMgr; private IPackageMemberMgr pkgMemberMgr; private IFileGroupMgr fileGroupMgr; private IImportRefactorer refactor; /** The empty package we're moving members into */ private int destPkgId; /** The source package that we create file groups in (file groups can't be in import) */ private int srcPkgId; /** IDs of all the files that we're creating in our test harness */ private int f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16; /** IDs of all the actions that we're creating in our test harness */ private int a1, a2, a3, a4, a5; /** IDs of all the file groups that we're creating in our test harness */ private int fg1, fg2; /*=====================================================================================* * SETUP/TEARDOWN *=====================================================================================*/ /** * Method called before each test case - sets up default configuration. * @throws Exception */ @Before public void setUp() throws Exception { /* get a new empty BuildStore */ buildStore = CommonTestUtils.getEmptyBuildStore(); /* fetch the associated managers */ fileMgr = buildStore.getFileMgr(); actionMgr = buildStore.getActionMgr(); pkgMgr = buildStore.getPackageMgr(); pkgMemberMgr = buildStore.getPackageMemberMgr(); fileGroupMgr = buildStore.getFileGroupMgr(); /* this is the object under test */ refactor = new ImportRefactorer(buildStore); /* source package for file groups (they can't exist in the import package) */ srcPkgId = pkgMgr.addPackage("srcPkg"); /* we're moving to this package */ destPkgId = pkgMgr.addPackage("MyPkg"); /* * Create the following "import" structure, from which all of our tests will operate * * f1 * f2 * f3 * f4 - a1 - f9 - a3 - f14 * f9 - a4 - f15 * f9 - a5 - f16 * f5 - a1 - f10 - a3 * f10 - a4 - f15 * f10 - a5 - f16 * f6 - a2 - f11 - a3 * f7 - a2 - f12 - a3 * f8 - a2 - f13 - a3 * * fg1 * fg2 * */ int parentActionId = actionMgr.getRootAction("root"); int actionDirId = fileMgr.getPath("/"); f1 = fileMgr.addFile("@workspace/a/b/file1"); f2 = fileMgr.addFile("@workspace/a/b/file2"); f3 = fileMgr.addFile("@workspace/a/b/file3"); f4 = fileMgr.addFile("@workspace/a/b/file4"); f5 = fileMgr.addFile("@workspace/a/c/file5"); f6 = fileMgr.addFile("@workspace/a/c/file6"); f7 = fileMgr.addFile("@workspace/a/c/file7"); f8 = fileMgr.addFile("@workspace/a/c/file8"); f9 = fileMgr.addFile("@workspace/a/c/file9"); f10 = fileMgr.addFile("@workspace/a/c/file10"); f11 = fileMgr.addFile("@workspace/a/c/file11"); f12 = fileMgr.addFile("@workspace/a/c/file12"); f13 = fileMgr.addFile("@workspace/a/c/file13"); f14 = fileMgr.addFile("@workspace/a/c/file14"); f15 = fileMgr.addFile("@workspace/a/c/file15"); f16 = fileMgr.addFile("@workspace/a/c/file16"); a1 = actionMgr.addShellCommandAction(parentActionId, actionDirId, "a1"); a2 = actionMgr.addShellCommandAction(parentActionId, actionDirId, "a2"); a3 = actionMgr.addShellCommandAction(parentActionId, actionDirId, "a3"); a4 = actionMgr.addShellCommandAction(parentActionId, actionDirId, "a4"); a5 = actionMgr.addShellCommandAction(parentActionId, actionDirId, "a5"); fg1 = fileGroupMgr.newSourceGroup(srcPkgId); fg2 = fileGroupMgr.newSourceGroup(srcPkgId); /* add file access relationships - as shown in the diagram */ actionMgr.addFileAccess(a1, f4, OperationType.OP_READ); actionMgr.addFileAccess(a1, f5, OperationType.OP_READ); actionMgr.addFileAccess(a1, f9, OperationType.OP_WRITE); actionMgr.addFileAccess(a1, f10, OperationType.OP_WRITE); actionMgr.addFileAccess(a2, f6, OperationType.OP_READ); actionMgr.addFileAccess(a2, f7, OperationType.OP_READ); actionMgr.addFileAccess(a2, f8, OperationType.OP_READ); actionMgr.addFileAccess(a2, f11, OperationType.OP_WRITE); actionMgr.addFileAccess(a2, f12, OperationType.OP_WRITE); actionMgr.addFileAccess(a2, f13, OperationType.OP_WRITE); actionMgr.addFileAccess(a3, f9, OperationType.OP_READ); actionMgr.addFileAccess(a3, f10, OperationType.OP_READ); actionMgr.addFileAccess(a3, f11, OperationType.OP_READ); actionMgr.addFileAccess(a3, f12, OperationType.OP_READ); actionMgr.addFileAccess(a3, f13, OperationType.OP_READ); actionMgr.addFileAccess(a3, f14, OperationType.OP_WRITE); actionMgr.addFileAccess(a4, f9, OperationType.OP_READ); actionMgr.addFileAccess(a4, f10, OperationType.OP_READ); actionMgr.addFileAccess(a4, f15, OperationType.OP_WRITE); actionMgr.addFileAccess(a5, f9, OperationType.OP_READ); actionMgr.addFileAccess(a5, f10, OperationType.OP_READ); actionMgr.addFileAccess(a5, f16, OperationType.OP_WRITE); } /*-------------------------------------------------------------------------------------*/ /** * Method called after each test cases - closes the BuildStore. * @throws Exception */ @After public void tearDown() throws Exception { buildStore.close(); } /*=====================================================================================* * HELPER METHODS *=====================================================================================*/ /** * Fetch the members in the destination package, to check what was moved. * * @param type The type of result we're looking for (TYPE_ANY, TYPE_ACTION, etc). * @return The members that were actually refactored into our destination package. We * extract all TYPE_FILE members because they're not interesting. */ private MemberDesc[] getResult(int type) { MemberDesc result[] = pkgMemberMgr.getMembersInPackage(destPkgId, IPackageMemberMgr.SCOPE_NONE, type); /* remove any files that we may have collected (files aren't shown in a diagram) */ List<MemberDesc> filtered = new ArrayList<IPackageMemberMgr.MemberDesc>(); for (int i = 0; i < result.length; i++) { if (result[i].memberType != IPackageMemberMgr.TYPE_FILE) { filtered.add(result[i]); } } return filtered.toArray(new MemberDesc[filtered.size()]); } /*-------------------------------------------------------------------------------------*/ /** * Helper method for building a MemberDesc list. Used only for simplifying test cases. * * @param args Any number of pairs of elements. The first of each pair is the type of * the member ('a' for action, 'f' for file, 'g' for group). The second * of each pair is the ID for the action, file or group. * @return The MemberDesc list. */ private List<MemberDesc> buildList(Object... args) { if ((args.length % 2) != 0) { throw new FatalBuildStoreError("Must have an even number of arguments"); } List<MemberDesc> resultList = new ArrayList<MemberDesc>(); for (int i = 0; i != args.length; ) { char type = (Character)args[i++]; int id = (Integer)args[i++]; int memberType; if (type == 'a') { memberType = IPackageMemberMgr.TYPE_ACTION; } else if (type == 'f') { memberType = IPackageMemberMgr.TYPE_FILE; } else if (type == 'g') { memberType = IPackageMemberMgr.TYPE_FILE_GROUP; } else { throw new FatalBuildStoreError("Invalid member type: " + type); } MemberDesc newMember = new MemberDesc(memberType, id, 0, 0); resultList.add(newMember); } return resultList; } /*-------------------------------------------------------------------------------------*/ /** * Helper method for comparing a file group's content against it's expected * membership. The ordering of the members is ignored, and duplicates will * not be accounted for correctly. * * @param fileGroupId The ID of the file group. * @param expected An array of expected ID values. */ private void validateFileGroupContents(int fileGroupId, Integer[] expected) { Integer actual[] = fileGroupMgr.getPathIds(fileGroupId); assertNotNull(actual); assertEquals(expected.length, actual.length); /* now look for the presence of all the members */ for (int i = 0; i < expected.length; i++) { boolean found = false; for (int j = 0; j < actual.length; j++) { if (actual[j] == expected[i]) { found = true; } } if (!found) { fail("Unable to find expected file group member: " + expected[i]); } } } /*-------------------------------------------------------------------------------------*/ /** * Validate that a package member belongs to a specific package. * * @param pkgId The package that we expect the member to be in. * @param memberType The type of member (TYPE_FILE, TYPE_FILE_GROUP, etc). * @param memberId The ID of the member. */ private void validatePackage(int pkgId, int memberType, int memberId) { PackageDesc desc = pkgMemberMgr.getPackageOfMember(memberType, memberId); assertEquals(pkgId, desc.pkgId); } /*-------------------------------------------------------------------------------------*/ /** * Validate that an action, and its input and output file groups are correct. This method * is called by all of our test* methods. * * @param destPkgId The ID of the package we're moving things to. * @param actionId The action we're validating * @param inputFiles The array of files we're expecting to see at the input. * @param outputFiles The array of files we're expecting to see on the output. */ private void validateInputsOutputs(int destPkgId, int actionId, Integer[] inputFiles, Integer[] outputFiles) { validatePackage(destPkgId, IPackageMemberMgr.TYPE_ACTION, actionId); Integer inputSlotValue = (Integer) actionMgr.getSlotValue( actionId, actionMgr.getSlotByName(actionId, "Input")); Integer outputSlotValue = (Integer) actionMgr.getSlotValue( actionId, actionMgr.getSlotByName(actionId, "Output")); assertNotNull(inputSlotValue); assertNotNull(outputSlotValue); /* confirm that each of the input/output file groups are in destPkgId */ validatePackage(destPkgId, IPackageMemberMgr.TYPE_FILE_GROUP, inputSlotValue); validatePackage(destPkgId, IPackageMemberMgr.TYPE_FILE_GROUP, outputSlotValue); /* * Confirm the membership of the input file group. Given that it could be any type * of group, we must expand the content of the group in order to validate it. */ String actualInputs[] = fileGroupMgr.getExpandedGroupFiles(inputSlotValue); List<String> expectedInputs = new ArrayList<String>(); for (int i = 0; i < inputFiles.length; i++) { expectedInputs.add(fileMgr.getPathName(inputFiles[i], true)); } String expectedInputArray[] = expectedInputs.toArray(new String[0]); assertTrue(CommonTestUtils.sortedArraysEqual(expectedInputArray, actualInputs)); /* confirm the membership of the output file group */ Integer actualOutputs[] = fileGroupMgr.getPathIds(outputSlotValue); assertTrue(CommonTestUtils.sortedArraysEqual(outputFiles, actualOutputs)); } /*=====================================================================================* * TEST METHODS *=====================================================================================*/ /** * Test base cases for MoveToPackage. This includes basic error checking and validation * of input. */ @Test public void testBaseCases() { /* test with empty list */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, new ArrayList<MemberDesc>()); multiOp.redo(); assertEquals(0, getResult(IPackageMemberMgr.TYPE_ANY).length); } catch (CanNotRefactorException e) { fail(); } /* test with null list */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, null); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.INVALID_MEMBER, e.getCauseCode()); assertEquals(-1, (int)e.getCauseIDs()[0]); } /* test with invalid package ID */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, 1389, buildList('f', f1)); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.INVALID_PACKAGE, e.getCauseCode()); assertEquals(1389, (int)e.getCauseIDs()[0]); } /* test with an invalid member type */ try { List<MemberDesc> members = new ArrayList<MemberDesc>(); members.add(new MemberDesc(IPackageMemberMgr.TYPE_FILE, f1, 0, 0)); members.add(new MemberDesc(1357, f1, 0, 0)); MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, members); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.INVALID_MEMBER, e.getCauseCode()); assertEquals(1357, (int)e.getCauseIDs()[0]); } /* test with two invalid file IDs (mixed in with other valid members) */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('a', a1, 'f', f2, 'f', 1000, 'f', f3, 'f', 2000, 'a', a2)); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.INVALID_PATH, e.getCauseCode()); Integer badPaths[] = e.getCauseIDs(); assertEquals(2, badPaths.length); assertEquals(1000, (int)badPaths[0]); assertEquals(2000, (int)badPaths[1]); } /* test with two invalid actions (and other valid members) */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('a', a1, 'f', f2, 'a', 1234, 'f', f3, 'a', 5678, 'a', a2)); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.INVALID_ACTION, e.getCauseCode()); Integer badActions[] = e.getCauseIDs(); assertEquals(2, badActions.length); assertEquals(1234, (int)badActions[0]); assertEquals(5678, (int)badActions[1]); } /* test with two invalid file groups (and other valid members) */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('a', a1, 'g', 1359, 'g', fg2, 'g', fg1, 'g', 1357, 'g', 1358)); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.INVALID_FILE_GROUP, e.getCauseCode()); Integer badGroups[] = e.getCauseIDs(); assertEquals(3, badGroups.length); assertEquals(1359, (int)badGroups[0]); assertEquals(1357, (int)badGroups[1]); assertEquals(1358, (int)badGroups[2]); } } /*-------------------------------------------------------------------------------------*/ /** * Test that any "loose" files that aren't attached to any actions are placed into a single * file group in the destination package. */ @Test public void testLooseFiles() { /* move three loose files into a package */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f3, 'f', f1, 'f', f2)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Validate that the package now has a single file group containing those three files. * Also, each of the files must have been moved into the new package. */ MemberDesc members[] = getResult(IPackageMemberMgr.TYPE_ANY); assertEquals(1, members.length); MemberDesc fileGroup = members[0]; assertEquals(IPackageMemberMgr.TYPE_FILE_GROUP, fileGroup.memberType); validateFileGroupContents(fileGroup.memberId, new Integer[] {f1, f2, f3}); validatePackage(destPkgId, IPackageMemberMgr.TYPE_FILE, f1); validatePackage(destPkgId, IPackageMemberMgr.TYPE_FILE, f2); validatePackage(destPkgId, IPackageMemberMgr.TYPE_FILE, f3); } /*-------------------------------------------------------------------------------------*/ /** * Test that any "loose" files which out out of range of the package's root will cause * an exception. */ @Test public void testLooseFilesOutOfRange() { /* set the source root of the package to @workspace/a/b */ IPackageRootMgr pkgRootMgr = buildStore.getPackageRootMgr(); assertEquals(ErrorCode.OK, pkgRootMgr.setPackageRoot( destPkgId, IPackageRootMgr.SOURCE_ROOT, fileMgr.getPath("@workspace/a/b"))); /* move three loose files into a package - f6 and f7 are in @workspace/a/c */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f3, 'f', f6, 'f', f7)); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.PATH_OUT_OF_RANGE, e.getCauseCode()); assertTrue(CommonTestUtils.sortedArraysEqual(new Integer[] {f6, f7}, e.getCauseIDs())); } } /*-------------------------------------------------------------------------------------*/ /** * Test moving of action a1. */ @Test public void testMoveActionA1() { try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('a', a1)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Package should now contain: * - Input file group: {f4, f5} * - Action a1 * - Output file group: {f9, f10} */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(1, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(2, fileGroups.length); /* confirm that action A1 has an input and output slot connected, and that the file groups are correct */ validateInputsOutputs(destPkgId, a1, new Integer[] {f4, f5}, new Integer[] {f9, f10}); } /*-------------------------------------------------------------------------------------*/ /** * Test moving a2 */ @Test public void testMoveActionA2() { try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('a', a2)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Package should now contain: * - Input file group: {f6, f7, f8} * - Action a2 * - Output file group: {f11, f12, f13} */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(1, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(2, fileGroups.length); /* confirm that action A1 has an input and output slot connected, and that the file groups are correct */ validateInputsOutputs(destPkgId, a2, new Integer[] {f6, f7, f8}, new Integer[] {f11, f12, f13}); } /*-------------------------------------------------------------------------------------*/ /** * Test moving f10 */ @Test public void testMoveFileF10() { try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f10)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Package should now contain: * - Input file group: {f4, f5} * - Action a1 * - Output file group: {f9, f10} */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(1, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(2, fileGroups.length); /* confirm that action A1 has an input and output slot connected, and that the file groups are correct */ validateInputsOutputs(destPkgId, a1, new Integer[] {f4, f5}, new Integer[] {f9, f10}); } /*-------------------------------------------------------------------------------------*/ /** * Test moving f12 */ @Test public void testMoveFileF12() { try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f12)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Package should now contain: * - Input file group: {f6, f7, f8} * - Action a2 * - Output file group: {f11, f12, f13} */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(1, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(2, fileGroups.length); /* confirm that action A1 has an input and output slot connected, and that the file groups are correct */ validateInputsOutputs(destPkgId, a2, new Integer[] {f6, f7, f8}, new Integer[] {f11, f12, f13}); } /*-------------------------------------------------------------------------------------*/ /** * Test moving f10 and f12 */ @Test public void testMoveFileF1012() { try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f12, 'f', f10)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Package should now contain: * - Input file group: {f4, f5} * - Action a1 * - Output file group: {f9, f10} * AND * - Input file group: {f6, f7, f8} * - Action a2 * - Output file group: {f11, f12, f13} */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(2, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(4, fileGroups.length); /* confirm that action A1 has an input and output slot connected, and that the file groups are correct */ validateInputsOutputs(destPkgId, a1, new Integer[] {f4, f5}, new Integer[] {f9, f10}); validateInputsOutputs(destPkgId, a2, new Integer[] {f6, f7, f8}, new Integer[] {f11, f12, f13}); } /*-------------------------------------------------------------------------------------*/ /** * Test chain where multiple actions converge into a single action. */ @Test public void testMoveFileF14() { try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f14)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Package should now contain: * - Input file group: {f4, f5} * - Action a1 * - Output file group: {f9, f10} * AND * - Input file group: {f6, f7, f8} * - Action a2 * - Output file group: {f11, f12, f13} * AND * - Input file group: {f9, f10, f11, f12, f13} * - Action a3 * - Output file group: {f14} */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(3, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(6, fileGroups.length); /* confirm that action A1 has an input and output slot connected, and that the file groups are correct */ validateInputsOutputs(destPkgId, a1, new Integer[] {f4, f5}, new Integer[] {f9, f10}); validateInputsOutputs(destPkgId, a2, new Integer[] {f6, f7, f8}, new Integer[] {f11, f12, f13}); validateInputsOutputs(destPkgId, a3, new Integer[] {f9, f10, f11, f12, f13}, new Integer[] {f14}); } /*-------------------------------------------------------------------------------------*/ /** * Test chain where a single action splits out into multiple actions.. */ @Test public void testMoveFileF14F15() { try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f15, 'f', f16)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Package should now contain: * - Input file group: {f4, f5} * - Action a1 * - Output file group: {f9, f10} * AND * - Input file group: {f9, f10} * - Action a4 * - Output file group: {f15} * AND * - Input file group: {f9, f10} * - Action a5 * - Output file group: {f16} */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(3, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(4, fileGroups.length); /* confirm that action A1 has an input and output slot connected, and that the file groups are correct */ validateInputsOutputs(destPkgId, a1, new Integer[] {f4, f5}, new Integer[] {f9, f10}); validateInputsOutputs(destPkgId, a4, new Integer[] {f9, f10}, new Integer[] {f15}); validateInputsOutputs(destPkgId, a5, new Integer[] {f9, f10}, new Integer[] {f16}); } /*-------------------------------------------------------------------------------------*/ /** * Test moving an action that writes into /home (which is out of range of the package). */ @Test public void testMoveWriteToOutOfRange() { /* create a new file /tmp/foo, that action a1 writes to */ int fTmp = fileMgr.addFile("/home/foo"); assertTrue(fTmp > 0); actionMgr.addFileAccess(a1, fTmp, OperationType.OP_WRITE); /* try the move - it will fail */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('a', a1)); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.PATH_OUT_OF_RANGE, e.getCauseCode()); Integer ids[] = e.getCauseIDs(); assertEquals(1, ids.length); assertEquals(Integer.valueOf(fTmp), ids[0]); } } /*-------------------------------------------------------------------------------------*/ /** * Test moving a non-atomic action ( */ @Test public void testMoveNonAtomic() { /* create a child action for a1 */ int actionDirId = fileMgr.getPath("/"); int a1Child = actionMgr.addShellCommandAction(a1, actionDirId, "a1Child"); /* move a chain, which has a1 in it */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f15, 'f', f16)); multiOp.redo(); fail(); } catch (CanNotRefactorException e) { assertEquals(Cause.ACTION_NOT_ATOMIC, e.getCauseCode()); assertEquals(a1, (int)(e.getCauseIDs()[0])); } } /*-------------------------------------------------------------------------------------*/ /** * Test moving an action that uses a subset of a previous action's output, and therefore * requires a filter. To do this, we must add a new relationship: f10 -> a6 -> f17. Note * that a6 only depends on f10 (not f9) and therefore a subset of a1's output is required. */ @Test public void testFilterOnSingleFileGroup() { /* set up f17 and a6, and their relationship */ int parentActionId = actionMgr.getRootAction("root"); int actionDirId = fileMgr.getPath("/"); int f17 = fileMgr.addFile("@workspace/a/c/file17"); int a6 = actionMgr.addShellCommandAction(parentActionId, actionDirId, "a6"); actionMgr.addFileAccess(a6, f10, OperationType.OP_READ); actionMgr.addFileAccess(a6, f17, OperationType.OP_WRITE); /* * Now proceed to move f17, which should result in: * {f4, f5} -> a1 -> {f9, f10} -> filter{f10} -> a6 -> {f17} * There should be a filter between a6 and the f9/f10 * file group, since we only need f10 (not f9). */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f17)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(2, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(4, fileGroups.length); /* confirm that actions a1 and a6 have the expected inputs and outputs */ validateInputsOutputs(destPkgId, a6, new Integer[] {f10}, new Integer[] {f17}); validateInputsOutputs(destPkgId, a1, new Integer[] {f4, f5}, new Integer[] {f9, f10}); /* confirm that the input to a6 is a filter group with "f10" as the filter */ int filterGroupId = (Integer) actionMgr.getSlotValue(a6, IActionMgr.INPUT_SLOT_ID); assertEquals(IFileGroupMgr.FILTER_GROUP, fileGroupMgr.getGroupType(filterGroupId)); assertEquals(1, fileGroupMgr.getGroupSize(filterGroupId)); assertEquals("ia:@workspace/a/c/file10", fileGroupMgr.getPathString(filterGroupId, 0)); } /*-------------------------------------------------------------------------------------*/ /** * Test the automatic creation of filters when a merge group is used. To do this, we * create a new action (a7) that reads f10, f11, f12. This should result in. * * {f4,f5} -> a1 -> {f9,f10} -> filter{f10} -> * {f6,f7,f8} -> a2 -> {f11,f12,f13} -> filter{f11,f12} -> merge{f10,f11,f12} -> a7 -> {f18} */ @Test public void testFilterOnMergeFileGroup() { /* set up a6, and it's read relationships with f10, f11, f12 and f18 */ int parentActionId = actionMgr.getRootAction("root"); int actionDirId = fileMgr.getPath("/"); int f18 = fileMgr.addFile("@workspace/a/c/file18"); int a7 = actionMgr.addShellCommandAction(parentActionId, actionDirId, "a7"); actionMgr.addFileAccess(a7, f10, OperationType.OP_READ); actionMgr.addFileAccess(a7, f11, OperationType.OP_READ); actionMgr.addFileAccess(a7, f12, OperationType.OP_READ); actionMgr.addFileAccess(a7, f18, OperationType.OP_WRITE); /* proceed to import */ try { MultiUndoOp multiOp = new MultiUndoOp(); refactor.moveMembersToPackage(multiOp, destPkgId, buildList('f', f18)); multiOp.redo(); } catch (CanNotRefactorException e) { fail(); } /* * Validate that we have the correct number of file groups and actions. */ MemberDesc actions[] = getResult(IPackageMemberMgr.TYPE_ACTION); assertEquals(3, actions.length); MemberDesc fileGroups[] = getResult(IPackageMemberMgr.TYPE_FILE_GROUP); assertEquals(8, fileGroups.length); /* * Validate the inputs and outputs of each action. */ validateInputsOutputs(destPkgId, a1, new Integer[] {f4, f5}, new Integer[] {f9, f10}); validateInputsOutputs(destPkgId, a2, new Integer[] {f6, f7, f8}, new Integer[] {f11, f12, f13}); validateInputsOutputs(destPkgId, a7, new Integer[] {f10, f11, f12}, new Integer[] {f18}); } /*-------------------------------------------------------------------------------------*/ }