From a7937c6cce66b6345974a9ee0d1cd49b9c8c670c Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Tue, 5 Jun 2012 16:23:34 +1000 Subject: [PATCH 1/4] Make sure document paths don't have a leading slash ('/'). This to prevent unwanted behaviour when uploading the same document via UI and the Rest API. Remove unnecessary methods from DocumentServiceImpl class. Handle unexpected errors due to invalid parameters when uploading. --- .../action/ProjectIterationFilesAction.java | 7 +++++- .../service/SourceDocResourceService.java | 5 ++-- .../org/zanata/service/DocumentService.java | 5 ++-- .../service/impl/DocumentServiceImpl.java | 23 +++---------------- .../impl/TranslationFileServiceImpl.java | 8 ++++--- 5 files changed, 19 insertions(+), 29 deletions(-) diff --git a/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java b/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java index 94bedb6b66..a75d633dc3 100644 --- a/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java +++ b/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.util.List; +import org.hibernate.validator.InvalidStateException; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; @@ -169,7 +170,7 @@ public void uploadDocumentFile() // TODO Copy Trans values // Extensions are hard-coded to GetText, since it is the only supported format at the time this.documentServiceImpl.saveDocument(this.projectSlug, this.iterationSlug, - this.documentFileUpload.getDocumentPath() + doc.getName(), doc, new StringSet(ExtensionType.GetText.toString()), + doc, new StringSet(ExtensionType.GetText.toString()), false); FacesMessages.instance().add(Severity.INFO, "Document file {0} uploaded.", this.documentFileUpload.getFileName()); @@ -178,6 +179,10 @@ public void uploadDocumentFile() { FacesMessages.instance().add(Severity.ERROR, zex.getMessage(), this.documentFileUpload.getFileName()); } + catch (InvalidStateException isex) + { + FacesMessages.instance().add(Severity.ERROR, "Invalid arguments"); + } } public boolean isFileUploadAllowed() diff --git a/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java b/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java index c0dfea0c34..375318e5b7 100644 --- a/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java +++ b/zanata-war/src/main/java/org/zanata/rest/service/SourceDocResourceService.java @@ -239,7 +239,7 @@ public Response post(Resource resource, @QueryParam("ext") Set extension // TODO No need for docId param since it's resource.getName() document = this.documentServiceImpl.saveDocument( - this.projectSlug, this.iterationSlug, resource.getName(), resource, extensions, copytrans); + this.projectSlug, this.iterationSlug, resource, extensions, copytrans); EntityTag etag = eTagUtils.generateETagForDocument(hProjectIteration, document.getDocId(), extensions); @@ -350,7 +350,8 @@ public Response putResource(@PathParam("id") String idNoSlash, Resource resource response = Response.ok(); } - document = this.documentServiceImpl.saveDocument(projectSlug, iterationSlug, id, resource, extensions, copytrans); + resource.setName( id ); + document = this.documentServiceImpl.saveDocument(projectSlug, iterationSlug, resource, extensions, copytrans); EntityTag etag = eTagUtils.generateETagForDocument(hProjectIteration, document.getDocId(), extensions); diff --git a/zanata-war/src/main/java/org/zanata/service/DocumentService.java b/zanata-war/src/main/java/org/zanata/service/DocumentService.java index 85c74253d6..dbf12fa141 100644 --- a/zanata-war/src/main/java/org/zanata/service/DocumentService.java +++ b/zanata-war/src/main/java/org/zanata/service/DocumentService.java @@ -35,13 +35,12 @@ public interface DocumentService * * @param projectSlug The document's project id. * @param iterationSlug The document's project iteration id. - * @param docId The document id. - * @param sourceDoc The document contents. + * @param sourceDoc The document to save. (If the document's name matches a docId already stored, it will be overwritten) * @param extensions Document extensions to save. * @param copyTrans Whether to copy translations from other projects or not. A true value does not guarantee that * this will happen, it is only a suggestion. * @return The created / updated document */ - public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, + public HDocument saveDocument( String projectSlug, String iterationSlug, Resource sourceDoc, Set extensions, boolean copyTrans ); } diff --git a/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java index ee014743b0..f1f953f18b 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/DocumentServiceImpl.java @@ -68,31 +68,14 @@ public class DocumentServiceImpl implements DocumentService private ApplicationConfiguration applicationConfiguration; - public DocumentServiceImpl() - { - } - - public DocumentServiceImpl(ProjectIterationDAO projectIterationDAO, - DocumentDAO documentDAO, - LocaleService localeService, - CopyTransService copyTransService, - ResourceUtils resourceUtils, - ApplicationConfiguration applicationConfiguration) - { - this.projectIterationDAO = projectIterationDAO; - this.documentDAO = documentDAO; - this.localeServiceImpl = localeService; - this.copyTransServiceImpl = copyTransService; - this.resourceUtils = resourceUtils; - this.applicationConfiguration = applicationConfiguration; - } - - public HDocument saveDocument( String projectSlug, String iterationSlug, String docId, Resource sourceDoc, + public HDocument saveDocument( String projectSlug, String iterationSlug, Resource sourceDoc, Set extensions, boolean copyTrans ) { // Only active iterations allow the addition of a document HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug); + String docId = sourceDoc.getName(); + HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, docId); HLocale hLocale = this.localeServiceImpl.validateSourceLocale( sourceDoc.getLang() ); diff --git a/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java b/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java index 969dc00600..d7da8695d0 100644 --- a/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/service/impl/TranslationFileServiceImpl.java @@ -100,13 +100,15 @@ private Resource parsePotFile( InputStream fileContents, String docPath, String PoReader2 poReader = new PoReader2(); // assume english as source locale Resource res = poReader.extractTemplate(new InputSource(fileContents), new LocaleId("en"), fileName); + // trim extra spaces + docPath = docPath.trim(); // get rid of leading slashes ("/") - if( docPath.startsWith("/") ) + while( docPath.startsWith("/") ) { docPath = docPath.substring(1); } - // Add a trailing slash ("/") if there isn't one - if( !docPath.endsWith("/") ) + // Add a trailing slash ("/") if there isn't one, and there is a need for one + if( docPath.length() > 0 && !docPath.endsWith("/") ) { docPath = docPath.concat("/"); } From 1ff6a9cb2e8d128efce167dc6ea0f364a505ed54 Mon Sep 17 00:00:00 2001 From: David Mason Date: Wed, 6 Jun 2012 12:00:20 +1000 Subject: [PATCH 2/4] add tooltips to doclist filter elements --- .../webtrans/client/resources/WebTransMessages.java | 9 +++++++++ .../zanata/webtrans/client/view/DocumentListView.java | 10 +++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java b/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java index 9b2eb37860..e0451d9c41 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/resources/WebTransMessages.java @@ -322,4 +322,13 @@ public interface WebTransMessages extends Messages @DefaultMessage("Show project-wide search view") String showProjectWideSearch(); + + @DefaultMessage("Only show documents that contain the search text with matching case") + String docListFilterCaseSensitiveDescription(); + + @DefaultMessage("Only show documents with full path and name in the search text") + String docListFilterExactMatchDescription(); + + @DefaultMessage("Enter text to filter the document list. Use commas (,) to separate multiple searches") + String docListFilterDescription(); } diff --git a/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java b/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java index 8c97851dd0..d65bc40d6f 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/client/view/DocumentListView.java @@ -79,14 +79,18 @@ interface DocumentListViewUiBinder extends UiBinder(); filterTextBox = new ClearableTextBox(resources, uiMessages); + initWidget(uiBinder.createAndBindUi(this)); + filterTextBox.setTitle(messages.docListFilterDescription()); // TODO set this from the presenter if possible - dataProvider = new ListDataProvider(); + caseSensitiveCheckBox.setTitle(messages.docListFilterCaseSensitiveDescription()); + exactSearchCheckBox.setTitle(messages.docListFilterExactMatchDescription()); - initWidget(uiBinder.createAndBindUi(this)); } @Override From c45527f2ecb93c4e0a11717ee822b26eb048a29b Mon Sep 17 00:00:00 2001 From: Carlos Munoz Date: Wed, 6 Jun 2012 13:28:25 +1000 Subject: [PATCH 3/4] Add redirect to origin page to avoid errors when uploading. Default redirect is not working, probably due to use of multipart form when uploading. --- .../zanata/action/ProjectIterationFilesAction.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java b/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java index a75d633dc3..7102d48c45 100644 --- a/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java +++ b/zanata-war/src/main/java/org/zanata/action/ProjectIterationFilesAction.java @@ -52,6 +52,8 @@ import org.zanata.service.TranslationFileService; import org.zanata.service.TranslationService; +import javax.faces.context.FacesContext; + @Name("projectIterationFilesAction") @Scope(ScopeType.PAGE) public class ProjectIterationFilesAction @@ -126,7 +128,7 @@ public TransUnitWords getTransUnitWordsForDocument(HDocument doc) } @Restrict("#{projectIterationFilesAction.fileUploadAllowed}") - public void uploadTranslationFile() + public String uploadTranslationFile() { TranslationsResource transRes = null; try @@ -157,10 +159,14 @@ public void uploadTranslationFile() { FacesMessages.instance().add(Severity.ERROR, zex.getMessage(), this.translationFileUpload.getFileName()); } + + // NB This needs to be done as for some reason seam is losing the parameters when redirecting + // This is efectively the same as returning void + return FacesContext.getCurrentInstance().getViewRoot().getViewId(); } @Restrict("#{projectIterationFilesAction.documentUploadAllowed}") - public void uploadDocumentFile() + public String uploadDocumentFile() { try { @@ -183,6 +189,10 @@ public void uploadDocumentFile() { FacesMessages.instance().add(Severity.ERROR, "Invalid arguments"); } + + // NB This needs to be done as for some reason seam is losing the parameters when redirecting + // This is efectively the same as returning void + return FacesContext.getCurrentInstance().getViewRoot().getViewId(); } public boolean isFileUploadAllowed() From 21c9f2e4882fb3b0c185f3d29f551f39bb1daf7d Mon Sep 17 00:00:00 2001 From: David Mason Date: Wed, 6 Jun 2012 17:57:06 +1000 Subject: [PATCH 4/4] add basic test for SearchResultsPresenter --- .../presenter/SearchResultsPresenterTest.java | 311 ++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 zanata-war/src/test/java/org/zanata/webtrans/client/presenter/SearchResultsPresenterTest.java diff --git a/zanata-war/src/test/java/org/zanata/webtrans/client/presenter/SearchResultsPresenterTest.java b/zanata-war/src/test/java/org/zanata/webtrans/client/presenter/SearchResultsPresenterTest.java new file mode 100644 index 0000000000..37945e9f02 --- /dev/null +++ b/zanata-war/src/test/java/org/zanata/webtrans/client/presenter/SearchResultsPresenterTest.java @@ -0,0 +1,311 @@ +/* + * Copyright 2012, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.webtrans.client.presenter; + +import static org.easymock.EasyMock.and; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.isA; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.reset; +import static org.easymock.EasyMock.verify; + +import java.util.ArrayList; + +import net.customware.gwt.presenter.client.EventBus; + +import org.easymock.Capture; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.zanata.webtrans.client.events.TransUnitUpdatedEvent; +import org.zanata.webtrans.client.events.TransUnitUpdatedEventHandler; +import org.zanata.webtrans.client.events.WorkspaceContextUpdateEvent; +import org.zanata.webtrans.client.events.WorkspaceContextUpdateEventHandler; +import org.zanata.webtrans.client.history.History; +import org.zanata.webtrans.client.history.Window; +import org.zanata.webtrans.client.history.Window.Location; +import org.zanata.webtrans.client.keys.KeyShortcut; +import org.zanata.webtrans.client.presenter.SearchResultsPresenter.Display; +import org.zanata.webtrans.client.resources.WebTransMessages; +import org.zanata.webtrans.client.rpc.CachingDispatchAsync; +import org.zanata.webtrans.shared.model.WorkspaceContext; + +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.HasClickHandlers; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.event.shared.GwtEvent.Type; +import com.google.gwt.user.client.ui.HasText; +import com.google.gwt.user.client.ui.HasValue; + +/** + * @author David Mason, damason@redhat.com + * + */ +@Test(groups = { "unit-tests" }) +public class SearchResultsPresenterTest +{ + + private static final int TOTAL_KEY_SHORTCUTS = 5; + + private static final String TEST_MESSAGE_NO_TEXT_FLOWS_SELECTED = "No text flows selected"; + private static final String TEST_MESSAGE_SELECT_ALL_TEXT_FLOWS_KEY_SHORTCUT = "Select all text flows"; + private static final String TEST_MESSAGE_FOCUS_SEARCH_PHRASE_KEY_SHORTCUT = "Focus search phrase"; + private static final String TEST_MESSAGE_FOCUS_REPLACEMENT_PHRASE_KEY_SHORTCUT = "Focus replacement phrase"; + private static final String TEST_MESSAGE_REPLACE_SELECTED_KEY_SHORTCUT = "Replace selected text flows"; + private static final String TEST_MESSAGE_TOGGLE_ROW_ACTION_BUTTONS = "Toggle row action buttons"; + + + //object under test + SearchResultsPresenter searchResultsPresenter; + + + ArrayList createdMocks; + Object[] allMocks; + + CachingDispatchAsync mockDispatcher; + Display mockDisplay; + EventBus mockEventBus; + History mockHistory; + KeyShortcutPresenter mockKeyShortcutPresenter; + WebTransMessages mockMessages; + Location mockWindowLocation; + WorkspaceContext mockWorkspaceContext; + + HasClickHandlers mockReplaceAllButton; + HasValue mockReplacementTextBox; + HasValue mockRequirePreviewChk; + HasClickHandlers mockSearchButton; + HasClickHandlers mockSelectAllButton; + HasValue mockSelectAllChk; + HasText mockSelectionInfoLabel; + + + Capture> capturedHistoryValueChangeHandler; + Capture capturedReplaceAllButtonClickHandler; + Capture> capturedReplacementTextBoxValueChangeHandler; + Capture> capturedRequirePreviewChkValueChangeHandler; + Capture capturedSearchButtonClickHandler; + Capture capturedSelectAllButtonClickHandler; + Capture> capturedSelectAllChkValueChangeHandler; + + Capture capturedTransUnitUpdatedEventHandler; + Capture capturedWorkspaceContextUpdatedEventHandler; + private Capture capturedKeyShortcuts; + + + + @BeforeClass + public void createMocks() + { + createAllMocks(); + createAllCaptures(); + } + + @SuppressWarnings("unchecked") + private void createAllMocks() + { + createdMocks = new ArrayList(); + + mockDispatcher = createAndAddMock(CachingDispatchAsync.class); + mockDisplay = createAndAddMock(Display.class); + mockEventBus = createAndAddMock(EventBus.class); + mockHistory = createAndAddMock(History.class); + mockKeyShortcutPresenter = createAndAddMock(KeyShortcutPresenter.class); + mockMessages = createAndAddMock(WebTransMessages.class); + mockWindowLocation = createAndAddMock(Window.Location.class); + mockWorkspaceContext = createAndAddMock(WorkspaceContext.class); + + mockReplaceAllButton = createAndAddMock(HasClickHandlers.class); + mockReplacementTextBox = createAndAddMock(HasValue.class); + mockRequirePreviewChk = createAndAddMock(HasValue.class); + mockSearchButton = createAndAddMock(HasClickHandlers.class); + mockSelectAllButton = createAndAddMock(HasClickHandlers.class); + mockSelectAllChk = createAndAddMock(HasValue.class); + mockSelectionInfoLabel = createAndAddMock(HasText.class); + + allMocks = createdMocks.toArray(); + } + + private void createAllCaptures() + { + capturedHistoryValueChangeHandler = new Capture>(); + capturedReplaceAllButtonClickHandler = new Capture(); + capturedReplacementTextBoxValueChangeHandler = new Capture>(); + capturedRequirePreviewChkValueChangeHandler = new Capture>(); + capturedSearchButtonClickHandler = new Capture(); + capturedSelectAllButtonClickHandler = new Capture(); + capturedSelectAllChkValueChangeHandler = new Capture>(); + + capturedTransUnitUpdatedEventHandler = new Capture(); + capturedWorkspaceContextUpdatedEventHandler = new Capture(); + + capturedKeyShortcuts = new Capture(); + } + + private T createAndAddMock(Class clazz) + { + T mock = createMock(clazz); + createdMocks.add(mock); + return mock; + } + + @BeforeMethod + public void beforeMethod() + { + resetAllMocks(); + resetAllCaptures(); + + setupDefaultMockExpectations(); + + searchResultsPresenter = new SearchResultsPresenter(mockDisplay, mockEventBus, + mockDispatcher, mockHistory, mockMessages, mockWorkspaceContext, + mockKeyShortcutPresenter, mockWindowLocation); + + } + + public void testExpectedActionsOnBind() + { + replayAllMocks(); + searchResultsPresenter.bind(); + verifyAllMocks(); + } + + private void setupDefaultMockExpectations() + { + boolean workspaceIsReadOnly = false; + + expectUiMessages(); + + expect(mockWorkspaceContext.isReadOnly()).andReturn(workspaceIsReadOnly).anyTimes(); + + expectDisplayComponentGetters(); + + mockSelectionInfoLabel.setText(TEST_MESSAGE_NO_TEXT_FLOWS_SELECTED); + expectLastCall().once(); + + mockDisplay.setReplaceAllButtonEnabled(false); + expectLastCall().once(); + + mockDisplay.setReplaceAllButtonVisible(!workspaceIsReadOnly); + expectLastCall().once(); + + expectHandlerRegistrations(); + + expect(mockKeyShortcutPresenter.registerKeyShortcut(capture(capturedKeyShortcuts))).andReturn(createMock(HandlerRegistration.class)).times(TOTAL_KEY_SHORTCUTS); + } + + private void expectUiMessages() + { + expect(mockMessages.noTextFlowsSelected()).andReturn(TEST_MESSAGE_NO_TEXT_FLOWS_SELECTED).anyTimes(); + expect(mockMessages.selectAllTextFlowsKeyShortcut()).andReturn(TEST_MESSAGE_SELECT_ALL_TEXT_FLOWS_KEY_SHORTCUT).anyTimes(); + expect(mockMessages.focusSearchPhraseKeyShortcut()).andReturn(TEST_MESSAGE_FOCUS_SEARCH_PHRASE_KEY_SHORTCUT).anyTimes(); + expect(mockMessages.focusReplacementPhraseKeyShortcut()).andReturn(TEST_MESSAGE_FOCUS_REPLACEMENT_PHRASE_KEY_SHORTCUT).anyTimes(); + expect(mockMessages.replaceSelectedKeyShortcut()).andReturn(TEST_MESSAGE_REPLACE_SELECTED_KEY_SHORTCUT).anyTimes(); + expect(mockMessages.toggleRowActionButtons()).andReturn(TEST_MESSAGE_TOGGLE_ROW_ACTION_BUTTONS).anyTimes(); + } + + private void expectDisplayComponentGetters() + { + expect(mockDisplay.getSelectionInfoLabel()).andReturn(mockSelectionInfoLabel).anyTimes(); + expect(mockDisplay.getSearchButton()).andReturn(mockSearchButton).anyTimes(); + expect(mockDisplay.getReplacementTextBox()).andReturn(mockReplacementTextBox).anyTimes(); + expect(mockDisplay.getSelectAllChk()).andReturn(mockSelectAllChk).anyTimes(); + expect(mockDisplay.getRequirePreviewChk()).andReturn(mockRequirePreviewChk).anyTimes(); + expect(mockDisplay.getReplaceAllButton()).andReturn(mockReplaceAllButton).anyTimes(); + expect(mockDisplay.getSelectAllButton()).andReturn(mockSelectAllButton).anyTimes(); + } + + private void expectHandlerRegistrations() + { + expectClickHandlerRegistration(mockSearchButton, capturedSearchButtonClickHandler); + expectValueChangeHandlerRegistration(mockReplacementTextBox, capturedReplacementTextBoxValueChangeHandler); + expectValueChangeHandlerRegistration(mockSelectAllChk, capturedSelectAllChkValueChangeHandler); + expectValueChangeHandlerRegistration(mockRequirePreviewChk, capturedRequirePreviewChkValueChangeHandler); + expectClickHandlerRegistration(mockReplaceAllButton, capturedReplaceAllButtonClickHandler); + expectClickHandlerRegistration(mockSelectAllButton, capturedSelectAllButtonClickHandler); + + expect(mockHistory.addValueChangeHandler(capture(capturedHistoryValueChangeHandler))).andReturn(createMock(HandlerRegistration.class)).once(); + + expectEventHandlerRegistration(TransUnitUpdatedEvent.getType(), TransUnitUpdatedEventHandler.class, capturedTransUnitUpdatedEventHandler); + expectEventHandlerRegistration(WorkspaceContextUpdateEvent.getType(), WorkspaceContextUpdateEventHandler.class, capturedWorkspaceContextUpdatedEventHandler); + } + + // copied from AppPresenterTest + /** + * Expect a single handler registration on a mock object, and capture the + * click handler in the given {@link Capture} + * + * @param mockObjectToClick + * @param captureForHandler + */ + private void expectClickHandlerRegistration(HasClickHandlers mockObjectToClick, Capture captureForHandler) + { + expect(mockObjectToClick.addClickHandler(and(capture(captureForHandler), isA(ClickHandler.class)))).andReturn(createMock(HandlerRegistration.class)).once(); + } + + private void expectValueChangeHandlerRegistration(HasValue mockObjectWithValue, Capture> captureForHandler) + { + expect(mockObjectWithValue.addValueChangeHandler(capture(captureForHandler))).andReturn(createMock(HandlerRegistration.class)).once(); + } + + //copied from AppPresenterTest + private void expectEventHandlerRegistration(Type expectedType, Class expectedClass, Capture handlerCapture) + { + expect(mockEventBus.addHandler(eq(expectedType), and(capture(handlerCapture), isA(expectedClass)))).andReturn(createMock(HandlerRegistration.class)).once(); + } + + private void resetAllCaptures() + { + capturedHistoryValueChangeHandler.reset(); + capturedReplaceAllButtonClickHandler.reset(); + capturedReplacementTextBoxValueChangeHandler.reset(); + capturedRequirePreviewChkValueChangeHandler.reset(); + capturedSearchButtonClickHandler.reset(); + capturedSelectAllButtonClickHandler.reset(); + capturedSelectAllChkValueChangeHandler.reset(); + + capturedTransUnitUpdatedEventHandler.reset(); + capturedWorkspaceContextUpdatedEventHandler.reset(); + + capturedKeyShortcuts.reset(); + } + + private void resetAllMocks() + { + reset(allMocks); + } + + private void replayAllMocks() + { + replay(allMocks); + } + + private void verifyAllMocks() + { + verify(allMocks); + } +}