/*******************************************************************************
* Copyright (c) 2011, 2015 Frank Appel and others.
* 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
* EclipseSource - ongoing development
******************************************************************************/
package org.eclipse.rap.rwt.internal.textsize;
import static org.eclipse.rap.rwt.internal.protocol.JsonUtil.createJsonArray;
import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementOperator.METHOD_MEASURE_ITEMS;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementOperator.METHOD_STORE_MEASUREMENTS;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementOperator.PARAM_ITEMS;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementOperator.PARAM_RESULTS;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementOperator.TYPE;
import static org.eclipse.rap.rwt.internal.textsize.MeasurementUtil.getId;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.eclipse.rap.json.JsonObject;
import org.eclipse.rap.json.JsonValue;
import org.eclipse.rap.rwt.internal.lifecycle.LifeCycleUtil;
import org.eclipse.rap.rwt.internal.lifecycle.PhaseId;
import org.eclipse.rap.rwt.internal.protocol.Operation.CallOperation;
import org.eclipse.rap.rwt.internal.remote.RemoteObjectImpl;
import org.eclipse.rap.rwt.internal.remote.RemoteObjectRegistry;
import org.eclipse.rap.rwt.remote.OperationHandler;
import org.eclipse.rap.rwt.testfixture.internal.Fixture;
import org.eclipse.rap.rwt.testfixture.internal.TestMessage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class MeasurementOperator_Test {
private static final FontData FONT_DATA_1 = new FontData( "arial", 12, SWT.NONE );
private static final FontData FONT_DATA_2 = new FontData( "courier", 14, SWT.BOLD );
private static final String TEXT_TO_MEASURE = "textToMeasure";
private static final int MODE = TextSizeUtil.STRING_EXTENT;
private static final MeasurementItem MEASUREMENT_ITEM_1
= new MeasurementItem( TEXT_TO_MEASURE, FONT_DATA_1, SWT.DEFAULT, MODE );
private static final MeasurementItem MEASUREMENT_ITEM_2
= new MeasurementItem( TEXT_TO_MEASURE, FONT_DATA_2, SWT.DEFAULT, MODE );
private Display display;
private MeasurementOperator operator;
@Before
public void setUp() {
Fixture.setUp();
display = new Display();
operator = MeasurementUtil.getMeasurementOperator();
Fixture.fakeNewRequest();
}
@After
public void tearDown() {
Fixture.tearDown();
}
@Test
public void testInitStartupProbes() {
removeRemoteObject( TYPE );
createProbe( FONT_DATA_1 );
MeasurementOperator measurementOperator = new MeasurementOperator();
assertEquals( 1, measurementOperator.getProbeCount() );
}
@Test
public void testOperationHandler_handleCall_onStartup() {
removeRemoteObject( TYPE );
LifeCycleUtil.setSessionDisplay( null );
createProbe( FONT_DATA_1 );
MeasurementOperator measurementOperator = new MeasurementOperator();
JsonObject parameters = createMeasurementResult( FONT_DATA_1, null );
getOperationHandler( TYPE ).handleCall( METHOD_STORE_MEASUREMENTS, parameters );
assertEquals( 0, measurementOperator.getProbeCount() );
}
@Test
public void testOperationHandler_handleCall() {
Fixture.fakePhase( PhaseId.PROCESS_ACTION );
operator.addProbeToMeasure( FONT_DATA_1 );
operator.addItemToMeasure( MEASUREMENT_ITEM_1 );
JsonObject parameters = createMeasurementResult( FONT_DATA_1, MEASUREMENT_ITEM_1 );
getOperationHandler( TYPE ).handleCall( METHOD_STORE_MEASUREMENTS, parameters );
assertEquals( 0, operator.getProbeCount() );
assertEquals( 0, operator.getItemCount() );
}
@Test
public void testOperationHandler_handleCall_triggersTextSizeRecalculation() {
Fixture.fakePhase( PhaseId.PROCESS_ACTION );
operator.addProbeToMeasure( FONT_DATA_1 );
operator.addItemToMeasure( MEASUREMENT_ITEM_1 );
Shell shell = new Shell( display );
Listener listener = mock( Listener.class );
shell.addListener( SWT.Resize, listener );
JsonObject parameters = createMeasurementResult( FONT_DATA_1, MEASUREMENT_ITEM_1 );
getOperationHandler( TYPE ).handleCall( METHOD_STORE_MEASUREMENTS, parameters );
verify( listener, times( 2 ) ).handleEvent( any( Event.class ) );
}
@Test
public void testAddItemToMeasure() {
operator.addItemToMeasure( MEASUREMENT_ITEM_1 );
checkMeasurementItemBuffering( MEASUREMENT_ITEM_1 );
}
@Test
public void testAddItemToMeasure_isIdempotent() {
operator.addItemToMeasure( MEASUREMENT_ITEM_1 );
operator.addItemToMeasure( MEASUREMENT_ITEM_1 );
checkMeasurementItemBuffering( MEASUREMENT_ITEM_1 );
}
@Test
public void testAddItemToMeasure_subsequent() {
operator.addItemToMeasure( MEASUREMENT_ITEM_1 );
operator.addItemToMeasure( MEASUREMENT_ITEM_2 );
assertEquals( 2, operator.getItemCount() );
assertSame( MEASUREMENT_ITEM_1, operator.getItems()[ 0 ] );
assertSame( MEASUREMENT_ITEM_2, operator.getItems()[ 1 ] );
}
@Test
public void testAddProbeToMeasure() {
operator.addProbeToMeasure( FONT_DATA_1 );
assertEquals( 1, operator.getProbeCount() );
assertSame( FONT_DATA_1, operator.getProbes()[ 0 ].getFontData() );
}
@Test
public void testAddProbeToMeasure_isIdempotent() {
operator.addProbeToMeasure( FONT_DATA_1 );
operator.addProbeToMeasure( FONT_DATA_1 );
assertEquals( 1, operator.getProbeCount() );
assertSame( FONT_DATA_1, operator.getProbes()[ 0 ].getFontData() );
}
@Test
public void testAddProbeToMeasure_subsequent() {
operator.addProbeToMeasure( FONT_DATA_1 );
operator.addProbeToMeasure( FONT_DATA_2 );
assertEquals( 2, operator.getProbeCount() );
assertTrue( probesContainFontData( FONT_DATA_1 ) );
assertTrue( probesContainFontData( FONT_DATA_2 ) );
}
@Test
public void testGetItemsToMeasureWithEmptyResult() {
MeasurementItem[] items = operator.getItems();
assertEquals( 0, items.length );
}
@Test
public void testRenderFontProbing() {
prepareTextProbing();
operator.renderMeasurementItems();
checkResponseContainsProbeCall();
}
@Test
public void testRenderStringMeasurements() {
prepareTextProbing();
operator.renderMeasurementItems();
checkResponseContainsMeasurementCall();
}
private boolean probesContainFontData( FontData fontData ) {
Probe[] probes = operator.getProbes();
for( Probe probe : probes ) {
if( probe.getFontData() == fontData ) {
return true;
}
}
return false;
}
private void removeRemoteObject( String type ) {
RemoteObjectRegistry.getInstance().remove( ( RemoteObjectImpl )getRemoteObject( type ) );
}
private OperationHandler getOperationHandler( String type ) {
return ( ( RemoteObjectImpl )getRemoteObject( type ) ).getHandler();
}
private void createProbe( FontData fontData ) {
getApplicationContext().getProbeStore().createProbe( fontData );
}
private JsonObject createMeasurementResult( FontData fontData, MeasurementItem measurementItem ) {
JsonObject results = new JsonObject();
if( fontData != null ) {
results.add( getId( fontData ), createJsonArray( 3, 4 ) );
}
if( measurementItem != null ) {
results.add( getId( measurementItem ), createJsonArray( 12, 4 ) );
}
return new JsonObject().add( PARAM_RESULTS, results );
}
private void checkMeasurementItemBuffering( MeasurementItem item ) {
assertEquals( 1, operator.getItemCount() );
assertSame( item, operator.getItems()[ 0 ] );
}
private void checkResponseContainsMeasurementCall() {
TestMessage message = Fixture.getProtocolMessage();
CallOperation operation = message.findCallOperation( TYPE, METHOD_MEASURE_ITEMS );
JsonValue itemsProperty = operation.getParameters().get( PARAM_ITEMS );
checkResponseContainsContent( getMeasurementCall(), itemsProperty.toString() );
}
private void checkResponseContainsProbeCall() {
TestMessage message = Fixture.getProtocolMessage();
CallOperation operation = message.findCallOperation( TYPE, METHOD_MEASURE_ITEMS );
JsonValue itemsProperty = operation.getParameters().get( PARAM_ITEMS );
checkResponseContainsContent( getProbeCall(), itemsProperty.toString() );
}
private void checkResponseContainsContent( String[] expected, String markup ) {
for( int i = 0; i < expected.length; i++ ) {
assertTrue( "Expected to contain '" + expected[ i ] + "', but was '" + markup + "'",
markup.contains( expected[ i ] ) );
}
}
private void prepareTextProbing() {
askForTextSizes();
Fixture.fakeResponseWriter();
}
private String[] getProbeCall() {
return new String[] {
",[\"arial\"],10,true,false,-1,true]",
",[\"helvetia\",\"ms sans serif\"],12,true,false,-1,true]",
",[\"Bogus Font Name\"],12,true,false,-1,true]"
};
}
private String[] getMeasurementCall() {
return new String[] {
",\"FirstString\",[\"arial\"],10,true,false,-1,false]",
",\"SecondString\",[\"helvetia\",\"ms sans serif\"],12,true,false,-1,false]",
",\"Weird \\\" String \\\\\",[\"Bogus Font Name\"],12,true,false,-1,false]"
};
}
private void askForTextSizes() {
Font[] fonts = new Font[] {
new Font( display, "arial", 10, SWT.BOLD ),
new Font( display, "helvetia, ms sans serif", 12, SWT.BOLD ),
new Font( display, "\"Bogus\" \\ Font \" Name", 12, SWT.BOLD )
};
TextSizeUtil.stringExtent( fonts[ 0 ], "FirstString" );
TextSizeUtil.stringExtent( fonts[ 1 ], "SecondString" );
TextSizeUtil.stringExtent( fonts[ 2 ], "Weird \" String \\" );
}
}