/** * Copyright (c) 2014 - 2017 Frank Appel * 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: * Frank Appel - initial API and implementation */ package com.codeaffine.eclipse.swt.widget.scrollable; import static com.codeaffine.eclipse.swt.widget.scrollable.ReconciliationHelper.stubReconciliation; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import com.codeaffine.eclipse.swt.util.ActionScheduler; import com.codeaffine.eclipse.swt.widget.scrollable.context.AdaptionContext; import com.codeaffine.eclipse.swt.widget.scrollable.context.Reconciliation; public class WatchDogTest { private NestingStructurePreserver nestingStructurePreserver; private StructureScrollableRedrawInsurance redrawInsurance; private ScrollBarUpdater horizontalScrollBarUpdater; private ScrollBarUpdater verticalScrollBarUpdater; private AdaptionContext<?> context; private Reconciliation reconciliation; private Visibility hScrollVisibility; private Visibility vScrollVisibility; private ActionScheduler scheduler; private LayoutTrigger layoutTrigger; private SizeObserver sizeObserver; private WatchDog watchDog; @Before public void setUp() { context = stubAdaptionContext(); horizontalScrollBarUpdater = mock( ScrollBarUpdater.class ); verticalScrollBarUpdater = mock( ScrollBarUpdater.class ); hScrollVisibility = mock( Visibility.class ); vScrollVisibility = mock( Visibility.class ); scheduler = mock( ActionScheduler.class ); layoutTrigger = mock( LayoutTrigger.class ); sizeObserver = mock( SizeObserver.class ); reconciliation = stubReconciliation(); nestingStructurePreserver = mock( NestingStructurePreserver.class ); redrawInsurance = mock( StructureScrollableRedrawInsurance.class ); watchDog = new WatchDog( context, horizontalScrollBarUpdater, verticalScrollBarUpdater, hScrollVisibility, vScrollVisibility, scheduler, layoutTrigger, sizeObserver, reconciliation, nestingStructurePreserver, redrawInsurance ); watchDog.layoutInitialized = true; } @Test public void initialSchedule() { verify( scheduler ).schedule( WatchDog.DELAY ); } @Test public void run() { watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( context ).updatePreferredSize(); order.verify( vScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( sizeObserver ).mustLayoutAdapter( any( AdaptionContext.class ) ); order.verify( sizeObserver ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).isVisible(); order.verify( hScrollVisibility ).isVisible(); order.verify( nestingStructurePreserver ).run(); order.verify( redrawInsurance ).run(); order.verify( scheduler ).schedule( WatchDog.DELAY ); verifyNoMoreInteractionOnDocs(); } @Test public void runWithLayoutInitialization() { watchDog.layoutInitialized = false; watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( context ).updatePreferredSize(); order.verify( layoutTrigger ).pull(); order.verify( sizeObserver ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).isVisible(); order.verify( hScrollVisibility ).isVisible(); order.verify( nestingStructurePreserver ).run(); order.verify( redrawInsurance ).run(); order.verify( scheduler ).schedule( WatchDog.DELAY ); verifyNoMoreInteractionOnDocs(); } @Test public void runIfVerticalScrollVisibilityHasChanged() { when( vScrollVisibility.hasChanged( any( AdaptionContext.class ) ) ).thenReturn( true ); watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( context ).updatePreferredSize(); order.verify( vScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( layoutTrigger ).pull(); order.verify( sizeObserver ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).isVisible(); order.verify( hScrollVisibility ).isVisible(); order.verify( nestingStructurePreserver ).run(); order.verify( redrawInsurance ).run(); order.verify( scheduler ).schedule( WatchDog.DELAY ); verifyNoMoreInteractionOnDocs(); } @Test public void runIfHorizontalScrollVisibilityHasChanged() { when( hScrollVisibility.hasChanged( any( AdaptionContext.class ) ) ).thenReturn( true ); watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( context ).updatePreferredSize(); order.verify( vScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( layoutTrigger ).pull(); order.verify( sizeObserver ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).isVisible(); order.verify( hScrollVisibility ).isVisible(); order.verify( nestingStructurePreserver ).run(); order.verify( redrawInsurance ).run(); order.verify( scheduler ).schedule( WatchDog.DELAY ); verifyNoMoreInteractionOnDocs(); } @Test public void runIfSizeObserverRequestsAdapterLayout() { when( sizeObserver.mustLayoutAdapter( any( AdaptionContext.class ) ) ).thenReturn( true ); watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( context ).updatePreferredSize(); order.verify( vScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( sizeObserver ).mustLayoutAdapter( any( AdaptionContext.class ) ); order.verify( layoutTrigger ).pull(); order.verify( sizeObserver ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).isVisible(); order.verify( hScrollVisibility ).isVisible(); order.verify( nestingStructurePreserver ).run(); order.verify( redrawInsurance ).run(); order.verify( scheduler ).schedule( WatchDog.DELAY ); verifyNoMoreInteractionOnDocs(); } @Test public void runIfVerticalScrollBarIsVisible() { when( vScrollVisibility.isVisible() ).thenReturn( true ); watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( context ).updatePreferredSize(); order.verify( vScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( sizeObserver ).mustLayoutAdapter( any( AdaptionContext.class ) ); order.verify( sizeObserver ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).isVisible(); order.verify( verticalScrollBarUpdater ).update(); order.verify( hScrollVisibility ).isVisible(); order.verify( nestingStructurePreserver ).run(); order.verify( redrawInsurance ).run(); order.verify( scheduler ).schedule( WatchDog.DELAY ); verifyNoMoreInteractionOnDocs(); } @Test public void runIfHorizontalScrollBarIsVisible() { when( hScrollVisibility.isVisible() ).thenReturn( true ); watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( context ).updatePreferredSize(); order.verify( vScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).hasChanged( any( AdaptionContext.class ) ); order.verify( sizeObserver ).mustLayoutAdapter( any( AdaptionContext.class ) ); order.verify( sizeObserver ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( hScrollVisibility ).update( any( AdaptionContext.class ) ); order.verify( vScrollVisibility ).isVisible(); order.verify( hScrollVisibility ).isVisible(); order.verify( horizontalScrollBarUpdater ).update(); order.verify( nestingStructurePreserver ).run(); order.verify( redrawInsurance ).run(); order.verify( scheduler ).schedule( WatchDog.DELAY ); verifyNoMoreInteractionOnDocs(); } @Test public void runAfterDisposal() { watchDog.widgetDisposed( null ); watchDog.run(); verifyNoMoreInteractionOnDocs(); } @Test public void ensureReconciliationClamp() { doNothing().when( reconciliation ).runWhileSuspended( any( Runnable.class ) ); watchDog.run(); InOrder order = docOrder(); order.verify( reconciliation ).runWhileSuspended( any( Runnable.class ) ); order.verify( scheduler ).schedule( WatchDog.DELAY ); order.verify( context, never() ).updatePreferredSize(); verify( vScrollVisibility, never() ).hasChanged( context ); verify( hScrollVisibility, never() ).hasChanged( context ); verify( sizeObserver, never() ).mustLayoutAdapter( context ); verify( sizeObserver, never() ).update( any( AdaptionContext.class ) ); verify( vScrollVisibility, never() ).update( any( AdaptionContext.class ) ); verify( hScrollVisibility, never() ).update( any( AdaptionContext.class ) ); verify( nestingStructurePreserver, never() ).run(); verify( vScrollVisibility, never() ).isVisible(); verify( hScrollVisibility, never() ).isVisible(); verifyNoMoreInteractionOnDocs(); } private InOrder docOrder() { return inOrder( context, horizontalScrollBarUpdater, verticalScrollBarUpdater, hScrollVisibility, vScrollVisibility, scheduler, layoutTrigger, sizeObserver, reconciliation, nestingStructurePreserver, redrawInsurance ); } private void verifyNoMoreInteractionOnDocs() { verifyNoMoreInteractions( horizontalScrollBarUpdater, verticalScrollBarUpdater, hScrollVisibility, vScrollVisibility, layoutTrigger, sizeObserver, reconciliation, nestingStructurePreserver, redrawInsurance ); } private AdaptionContext<?> stubAdaptionContext() { AdaptionContext<?> result = mock( AdaptionContext.class ); doAnswer( invocation -> stubAdaptionContext() ).when( result ).newContext(); return result; } }