@Test
	public void testSetToolAssociation() throws Exception {

		//
		// verify the default tool is the 'CodeBrowser'
		// verify that the VT tool is not in the tool chest (has not been imported)
		//
		removePreferences();
		initializeToolChestToJustCodeBrowser();

		//
		// verify that double-clicking a program launches its default tool (the CodeBrowser)
		//
		Project project = frontEndTool.getProject();
		DataTree tree = findComponent(frontEndTool.getToolFrame(), DataTree.class);

// TODO: move to method
		DomainFolder rootFolder = project.getProjectData().getRootFolder();
		Program p = buildProgram("notepad");
		rootFolder.createFile("notepad", p, TaskMonitor.DUMMY);
		env.release(p);

		GTreeNode rootNode = tree.getViewRoot();
		waitForTree(tree);
		waitForSwing();

		GTreeNode node = rootNode.getChild("notepad");
		Rectangle bounds = tree.getPathBounds(node.getTreePath());

		tree.setSelectedNode(node);
		waitForTree(tree);

		JTree jTree = (JTree) invokeInstanceMethod("getJTree", tree);
		clickMouse(jTree, MouseEvent.BUTTON1, bounds.x + 5, bounds.y + 5, 2, 0);
		waitForSwing();

		PluginTool tool = waitForTool("CodeBrowser", project);

		// close the CodeBrowser tool
		close(tool);
		waitForSwing();

		//
		// edit the association
		//
		DockingActionIf setAssociationsAction = getAction("Set Tool Associations");
		performAction(setAssociationsAction, false);

		SetToolAssociationsDialog associationDialog =
			waitForDialogComponent(SetToolAssociationsDialog.class);

		//
		// edit the association
		//
		// find the 'Program' entry
		GTable associationTable = findComponent(associationDialog.getComponent(), GTable.class);
		int rowCount = associationTable.getRowCount();
		int programRow = -1;
		for (int i = 0; i < rowCount; i++) {
			ContentHandler handler = (ContentHandler) associationTable.getValueAt(i, 0);
			if ("Program".equals(handler.getContentType())) {
				programRow = i;
				break;
			}
		}
		assertTrue("Unable to find the 'Program' entry in the associations table",
			programRow != -1);

		// select the program entry in the table
		final int finalProgramRow = programRow;
		runSwing(() -> associationTable.selectRow(finalProgramRow));

		// click the edit button
		JButton editButton = findButtonByText(associationDialog, "Edit");
		pressButton(editButton, false);

		// grab the new dialog
		PickToolDialog pickToolDialog = waitForDialogComponent(PickToolDialog.class);

		// select the VT tool
		String VTToolName = "Version Tracking";
		final GTable pickTable = findComponent(pickToolDialog.getComponent(), GTable.class);
		rowCount = pickTable.getRowCount();
		int toolRow = -1;
		for (int i = 0; i < rowCount; i++) {
			ToolTemplate template = (ToolTemplate) pickTable.getValueAt(i, 0);
			if (VTToolName.equals(template.getName())) {
				toolRow = i;
				break;
			}
		}
		assertTrue("Unable to find the 'Version Tracking' entry in the pick tool table",
			toolRow != -1);

		final int finalToolRow = toolRow;
		runSwing(() -> pickTable.selectRow(finalToolRow));

		// press OK
		JButton okButton = findButtonByText(pickToolDialog.getComponent(), "OK");
		pressButton(okButton);
		waitForSwing();

		// verify the new association is the VT tool
		ToolTemplate template = (ToolTemplate) associationTable.getValueAt(finalProgramRow, 1);
		assertEquals(VTToolName + " tool not made the association for Program", VTToolName,
			template.getName());

		// close the dialog
		final JButton associationDialogOKButton =
			findButtonByText(associationDialog.getComponent(), "OK");
		pressButton(associationDialogOKButton);

		//
		// Verify the new association
		//

		// verify the VT tool is now in the tool chest (has been imported as a result of the user
		// choice)
		ToolServices toolServices = frontEndTool.getToolServices();
		ToolChest toolChest = toolServices.getToolChest();
		ToolTemplate toolTemplate = toolChest.getToolTemplate(VTToolName);
		assertNotNull("Default tool not imported when chosen as the associated tool", toolTemplate);

		// double-click a program in the Front End
		clickMouse(jTree, MouseEvent.BUTTON1, bounds.x + 5, bounds.y + 5, 2, 0);
		waitForSwing();

		// make sure the VT tool is launched
		tool = waitForTool(VTToolName, project);

		// close the VT tool
		// we first have to close the wizard...
		WizardDialog wizard = waitForDialogComponent(WizardDialog.class);
		runSwing(() -> wizard.close());

		// ...then the tool
		close(tool);
		waitForSwing();

		//
		// edit the association
		//
		// find the 'Program' entry
		rowCount = associationTable.getRowCount();
		programRow = -1;
		for (int i = 0; i < rowCount; i++) {
			ContentHandler handler = (ContentHandler) associationTable.getValueAt(i, 0);
			if ("Program".equals(handler.getContentType())) {
				programRow = i;
				break;
			}
		}
		assertTrue("Unable to find the 'Program' entry in the associations table",
			programRow != -1);

		// select the program entry in the table
		final int newFinalProgramRow = programRow;
		runSwing(() -> associationTable.selectRow(newFinalProgramRow));

		// click the restore button
		JButton restoreButton =
			findButtonByText(associationDialog.getComponent(), "Restore Default");
		pressButton(restoreButton);

		// press OK
		JButton associationDialogOKButton2 =
			findButtonByText(associationDialog.getComponent(), "OK");
		pressButton(associationDialogOKButton2);

		//
		// Verify the new association
		//
		// double-click a program in the Front End
		clickMouse(jTree, MouseEvent.BUTTON1, bounds.x + 5, bounds.y + 5, 2, 0);
		waitForSwing();

		// make sure the 'CodeBrowser' tool is launched
		tool = waitForTool("CodeBrowser", project);

		// close the 'CodeBrowser' tool
		close(tool);
		waitForSwing();
	}
Tests for tool actions on the front end (Ghidra project window)
Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/ToolActionManagerTest.java