/**
* 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.context;
import static com.codeaffine.eclipse.swt.test.util.SWTEventHelper.trigger;
import static com.codeaffine.eclipse.swt.test.util.ShellHelper.createShell;
import static com.codeaffine.eclipse.swt.test.util.graphics.RectangleAssert.assertThat;
import static com.codeaffine.eclipse.swt.widget.scrollable.TreeHelper.createTree;
import static com.codeaffine.test.util.lang.ThrowableCaptor.thrownBy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import com.codeaffine.eclipse.swt.test.util.DisplayHelper;
import com.codeaffine.eclipse.swt.test.util.SWTIgnoreConditions.GtkPlatform;
import com.codeaffine.test.util.junit.ConditionalIgnoreRule;
import com.codeaffine.test.util.junit.ConditionalIgnoreRule.ConditionalIgnore;
public class BoundsReconciliationTest {
@Rule public final ConditionalIgnoreRule conditionalIgnoreRule = new ConditionalIgnoreRule();
@Rule public final DisplayHelper displayHelper = new DisplayHelper();
private BoundsReconciliation reconciliation;
private Composite adapter;
private Tree scrollable;
@Before
public void setUp() {
Shell shell = createShell( displayHelper );
adapter = new Composite( shell, SWT.NONE );
scrollable = createTree( adapter, 1, 1 );
reconciliation = new BoundsReconciliation( adapter, new ScrollableControl<>( scrollable ) );
}
@Test
public void run() {
Rectangle expected = adapter.getBounds();
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
public void runAfterScrollableBoundsHaveBeenChanged() {
Rectangle expected = new Rectangle( 100, 200, 300, 400 );
scrollable.setBounds( expected );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
public void runAfterScrollableSizeHaveBeenChanged() {
scrollable.setSize( 50, 60 );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualToRectangleOf( 0, 0, 50, 60 );
}
@Test
public void runAfterScrollableLocationHaveBeenChanged() {
scrollable.setLocation( 50, 60 );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualToRectangleOf( 50, 60, 0, 0 );
}
@Test
public void runAfterScrollableBoundsHaveChangedByTreeExpansion() {
Rectangle expected = adapter.getBounds();
scrollable.setBounds( new Rectangle( 100, 200, 300, 400 ) );
trigger( SWT.Expand ).on( scrollable );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
public void runAfterScrollableBoundsHaveChangedByTreeCollaps() {
Rectangle expected = adapter.getBounds();
scrollable.setBounds( new Rectangle( 100, 200, 300, 400 ) );
trigger( SWT.Collapse ).on( scrollable );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
public void subsequentRunWithoutChange() {
Rectangle expected = adapter.getBounds();
scrollable.setBounds( new Rectangle( 100, 200, 300, 400 ) );
trigger( SWT.Expand ).on( scrollable );
reconciliation.run();
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
public void subsequentRunWithChange() {
scrollable.setBounds( new Rectangle( 10, 20, 100, 500 ) );
trigger( SWT.Expand ).on( scrollable );
reconciliation.run();
scrollable.setBounds( new Rectangle( 100, 200, 300, 400 ) );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualToRectangleOf( 90, 180, 300, 400 );
}
@Test
public void subsequentRunWithLocationChange() {
scrollable.setBounds( new Rectangle( 10, 20, 100, 500 ) );
trigger( SWT.Expand ).on( scrollable );
reconciliation.run();
scrollable.setLocation( new Point( 100, 200 ) );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualToRectangleOf( 90, 180, 100, 500 );
}
@Test
public void runWithInitialBorderOffsetOnOwnerDrawnScrollableWithBorder() {
scrollable.dispose();
scrollable = createTree( adapter, 1, 1, SWT.BORDER );
scrollable.addListener( SWT.MeasureItem, evt -> {} );
reconciliation = new BoundsReconciliation( adapter, new ScrollableControl<>( scrollable ) );
Rectangle expected = adapter.getBounds();
scrollable.setBounds( -scrollable.getBorderWidth(), -scrollable.getBorderWidth(), 0, 0 );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
@ConditionalIgnore( condition = GtkPlatform.class )
public void runWithInitialBorderOffsetOnScrollableWithBorder() {
scrollable.dispose();
scrollable = createTree( adapter, 1, 1, SWT.BORDER );
reconciliation = new BoundsReconciliation( adapter, new ScrollableControl<>( scrollable ) );
Rectangle expected = adapter.getBounds();
scrollable.setBounds( -scrollable.getBorderWidth(), -scrollable.getBorderWidth(), 0, 0 );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
@ConditionalIgnore( condition = GtkPlatform.class )
public void runWithoutInitialBorderOffsetOnOwnerDrawnScrollable() {
scrollable.addListener( SWT.MeasureItem, evt -> {} );
Rectangle expected = new Rectangle( -2, -2, 0, 0 );
scrollable.setBounds( expected );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
public void runSuspended() {
Rectangle expected = adapter.getBounds();
reconciliation.runSuspended( () -> scrollable.setBounds( new Rectangle( 100, 200, 300, 400 ) ) );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
}
@Test
public void runSuspendedWithProblem() {
Rectangle expected = new Rectangle( 100, 200, 300, 400 );
RuntimeException toBeThrown = new RuntimeException();
Throwable problem = thrownBy( () -> reconciliation.runSuspended( stubRunnableWithProblem( toBeThrown ) ) );
scrollable.setBounds( expected );
reconciliation.run();
assertThat( adapter.getBounds() ).isEqualTo( expected );
assertThat( problem ).isSameAs( toBeThrown );
}
private static Runnable stubRunnableWithProblem( Throwable problem ) {
Runnable result = mock( Runnable.class );
doThrow( problem ).when( result ).run();
return result;
}
}