/**
* 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.navigationbar;
import static com.codeaffine.eclipse.swt.test.util.ShellHelper.createShell;
import static com.codeaffine.eclipse.swt.test.util.UiThreadHelper.runInOwnThreadWithReadAndDispatch;
import static com.codeaffine.eclipse.swt.widget.navigationbar.ActionControlImageAdapter.ARROW_DOWN;
import static com.codeaffine.eclipse.swt.widget.navigationbar.ActionControlImageAdapter.MINUS;
import static com.codeaffine.eclipse.swt.widget.navigationbar.ActionControlImageAdapter.PLUS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentCaptor.forClass;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import com.codeaffine.eclipse.swt.test.util.DisplayHelper;
import com.codeaffine.eclipse.swt.widget.action.ActionControlBuilder;
public class NavigationItemTest {
public final DisplayHelper displayHelper = new DisplayHelper();
private static final ActionControlBuilder SELECT_CONTROL_BUILDER = createActionControlBuilderSpy();
private static final ActionControlBuilder ADD_CONTROL_BUILDER = createActionControlBuilderSpy();
private static final ActionControlBuilder REMOVE_CONTROL_BUILDER = createActionControlBuilderSpy();
private static final NavigationItemModelElement SELECTION = new NavigationItemModelElement( "id", "displayName" );
private static final String ICON_NAME = "iconName";
private NavigationItemController controller;
private NavigationItem navigationItem;
private ImageProvider imageProvider;
private Map<String, Image> images;
private NavigationItemModel model;
private Shell parent;
@Before
public void setUp() {
images = new HashMap<>();
parent = createShell( displayHelper );
imageProvider = stubImageProvider( ICON_NAME, ARROW_DOWN, MINUS, PLUS );
model = stubNavigationItemModel( SELECTION );
controller = stubController();
navigationItem = new NavigationItem( imageProvider, model, controller, ICON_NAME );
}
@After
public void tearDown() {
images.values().forEach( image -> image.dispose() );
}
@Test
public void createControl() {
navigationItem.createControl( parent );
verify( imageProvider ).getImage( ICON_NAME );
verify( SELECT_CONTROL_BUILDER ).withImage( images.get( ARROW_DOWN ) );
verify( SELECT_CONTROL_BUILDER ).build( any( Composite.class ) );
verify( REMOVE_CONTROL_BUILDER ).withImage( images.get( MINUS ) );
verify( REMOVE_CONTROL_BUILDER ).build( any( Composite.class ) );
verify( ADD_CONTROL_BUILDER ).withImage( images.get( PLUS ) );
verify( ADD_CONTROL_BUILDER ).build( any( Composite.class ) );
verify( model ).addSelectionChangedListener( any( Runnable.class ) );
assertThat( navigationItem.getSelectionText() ).isEqualTo( SELECTION.getDisplayName() );
assertThat( parent.getChildren() ).hasSize( 1 );
}
@Test
public void selectionChanged() {
NavigationItemModelElement expected = new NavigationItemModelElement( "newId", "newSelection" );
navigationItem.createControl( parent );
equipWithSelection( model, expected );
runInOwnThreadWithReadAndDispatch( captureSelectionChangedListener() );
assertThat( navigationItem.getSelectionText() ).isEqualTo( expected.getDisplayName() );
}
@Test
public void dispose() {
navigationItem.createControl( parent );
Runnable listener = captureSelectionChangedListener();
parent.dispose();
verify( model ).removeSelectionChangedListener( listener );
verify( model ).dispose();
}
private Runnable captureSelectionChangedListener() {
ArgumentCaptor<Runnable> captor = forClass( Runnable.class );
verify( model ).addSelectionChangedListener( captor.capture() );
return captor.getValue();
}
private ImageProvider stubImageProvider( String ... imageNames ) {
ImageProvider result = mock( ImageProvider.class );
Stream.of( imageNames ).forEach( imageName -> equipWithImage( result, imageName ) );
return result;
}
private void equipWithImage( ImageProvider imageProvider, String iconName ) {
Image image = new Image( displayHelper.getDisplay(), 1, 1 );
images.put( iconName, image );
when( imageProvider.getImage( iconName ) ).thenReturn( image );
}
private static NavigationItemController stubController() {
NavigationItemController result = mock( NavigationItemController.class );
when( result.getAddControlBuilder() ).thenReturn( ADD_CONTROL_BUILDER );
when( result.getRemoveControlBuilder() ).thenReturn( REMOVE_CONTROL_BUILDER );
when( result.getSelectControlBuilder() ).thenReturn( SELECT_CONTROL_BUILDER );
return result;
}
private static NavigationItemModel stubNavigationItemModel( NavigationItemModelElement selection ) {
NavigationItemModel result = mock( NavigationItemModel.class );
equipWithSelection( result, selection );
return result;
}
private static void equipWithSelection( NavigationItemModel model, NavigationItemModelElement selection ) {
when( model.getSelection() ).thenReturn( selection );
}
@SuppressWarnings("unchecked")
private static ActionControlBuilder createActionControlBuilderSpy() {
ActionControlBuilder result = spy( new ActionControlBuilder( mock( Runnable.class ) ) );
when( result.withEnablement( any( BooleanSupplier.class ) ) ).thenReturn( result );
when( result.withImage( any( Image.class ) ) ).thenReturn( result );
when( result.withUpdateTrigger( ( any( Consumer.class ) ) ) ).thenReturn( result );
return result;
}
}