diff options
Diffstat (limited to 'toolkit/qa')
-rwxr-xr-x | toolkit/qa/complex/toolkit/Assert.java | 234 | ||||
-rwxr-xr-x | toolkit/qa/complex/toolkit/GridControl.java | 82 | ||||
-rwxr-xr-x | toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java | 51 | ||||
-rwxr-xr-x | toolkit/qa/complex/toolkit/makefile.mk | 1 |
4 files changed, 365 insertions, 3 deletions
diff --git a/toolkit/qa/complex/toolkit/Assert.java b/toolkit/qa/complex/toolkit/Assert.java new file mode 100755 index 000000000000..93b1a2c490e1 --- /dev/null +++ b/toolkit/qa/complex/toolkit/Assert.java @@ -0,0 +1,234 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + *************************************************************************/ + +package complex.toolkit; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import com.sun.star.uno.UnoRuntime; +import static org.junit.Assert.*; + +/** + * provides assertion capabilities not found in {@link org.junit.Assert} + * @author frank.schoenheit@oracle.com + */ +public class Assert +{ + // -------------------------------------------------------------------------------------------------------- + /** invokes a given method on a given object, and assures a certain exception is caught + * @param i_message + * is the message to print when the check fails + * @param i_object + * is the object to invoke the method on + * @param i_methodName + * is the name of the method to invoke + * @param i_methodArgs + * are the arguments to pass to the method. + * @param i_argClasses + * are the classes to assume for the arguments of the methods + * @param i_expectedExceptionClass + * is the class of the exception to be caught. If this is null, + * it means that <em>no</em> exception must be throw by invoking the method. + */ + public static void assertException( final String i_message, final Object i_object, final String i_methodName, + final Class[] i_argClasses, final Object[] i_methodArgs, final Class i_expectedExceptionClass ) + { + Class objectClass = i_object.getClass(); + + boolean noExceptionAllowed = ( i_expectedExceptionClass == null ); + + boolean caughtExpected = noExceptionAllowed ? true : false; + try + { + Method method = impl_getMethod( objectClass, i_methodName, i_argClasses ); + method.invoke(i_object, i_methodArgs ); + } + catch ( NoSuchMethodException e ) + { + StringBuilder message = new StringBuilder(); + message.append( "no such method: " ).append( objectClass.getName() ).append( "." ).append( i_methodName ).append( "( " ); + for ( int i=0; i<i_argClasses.length; ++i ) + { + message.append( i_argClasses[i].getName() ); + if ( i<i_argClasses.length - 1 ) + message.append( ", " ); + } + message.append( " )" ); + fail( message.toString() ); + } + catch ( InvocationTargetException e ) + { + caughtExpected = noExceptionAllowed + ? false + : ( e.getTargetException().getClass().equals( i_expectedExceptionClass ) ); + } + catch( Exception e ) + { + caughtExpected = false; + } + + assertTrue( i_message, caughtExpected ); + } + + /** + * retrieves a method, given by name and parameter signature, from the given class + * + * The method does somewhat more than simply calling {@link Class.getMethod}. In particular, it recognizes + * primitiive parameter types, and attempts to find a method taking the given primitive type, instead of the + * type represented by the parameter class. + * + * For instance, if you have a method <code>foo( int )</code>, {@link Class.getMethod} would not return this + * method when you pass <code>Integer.class</code>. <code>impl_getMethod</code> will recognize this, and + * properly retrieve the method. + * + * Note: <code>impl_getMethod</code> is limited in that it will not try all possible combinations of primitive + * and non-primitive types. That is, a method like <code>foo( int, Integer, int )</code> is likely to not be + * found. + * + * @param i_obbjectClass + * @param i_methodName + * @param i_argClasses + * @return + */ + private static Method impl_getMethod( final Class i_objectClass, final String i_methodName, final Class[] i_argClasses ) throws NoSuchMethodException + { + try + { + return i_objectClass.getMethod( i_methodName, i_argClasses ); + } + catch ( NoSuchMethodException ex ) + { + } + + int substitutedTypes = 0; + int substitutedTypesLastRound = 0; + final Class[][] substitutionTable = new Class[][] { + new Class[] { Long.class, long.class }, + new Class[] { Integer.class, int.class }, + new Class[] { Short.class, short.class }, + new Class[] { Byte.class, byte.class }, + new Class[] { Double.class, double.class }, + new Class[] { Float.class, float.class }, + new Class[] { Character.class, char.class } + }; + do + { + substitutedTypes = 0; + final Class[] argClasses = new Class[ i_argClasses.length ]; + for ( int i=0; i < argClasses.length; ++i ) + { + argClasses[i] = i_argClasses[i]; + if ( substitutedTypes > substitutedTypesLastRound ) + continue; + + for ( int c=0; c<substitutionTable.length; ++c ) + { + if ( i_argClasses[i].equals( substitutionTable[c][0] ) ) + { + argClasses[i] = substitutionTable[c][1]; + ++substitutedTypes; + break; + } + } + } + if ( substitutedTypes == substitutedTypesLastRound ) + throw new NoSuchMethodException(); + substitutedTypesLastRound = substitutedTypes; + + try + { + return i_objectClass.getMethod( i_methodName, argClasses ); + } + catch ( NoSuchMethodException e ) + { + } + } + while ( substitutedTypes > 0 ); + throw new NoSuchMethodException(); + } + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param i_message is the message to print when the check fails + * @param i_object is the object to invoke the method on + * @param i_methodName is the name of the method to invoke + * @param i_methodArgs are the arguments to pass to the method. Those implicitly define + * the classes of the arguments of the method which is called. + * @param i_expectedExceptionClass is the class of the exception to be caught. If this is null, + * it means that <em>no</em> exception must be throw by invoking the method. + */ + public static void assertException( final String i_message, final Object i_object, final String i_methodName, + final Object[] i_methodArgs, final Class i_expectedExceptionClass ) + { + Class[] argClasses = new Class[ i_methodArgs.length ]; + for ( int i=0; i<i_methodArgs.length; ++i ) + argClasses[i] = i_methodArgs[i].getClass(); + assertException( i_message, i_object, i_methodName, argClasses, i_methodArgs, i_expectedExceptionClass ); + } + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param i_object is the object to invoke the method on + * @param i_methodName is the name of the method to invoke + * @param i_methodArgs are the arguments to pass to the method. Those implicitly define + * the classes of the arguments of the method which is called. + * @param i_expectedExceptionClass is the class of the exception to be caught. If this is null, + * it means that <em>no</em> exception must be throw by invoking the method. + */ + public static void assertException( final Object i_object, final String i_methodName, final Object[] i_methodArgs, + final Class i_expectedExceptionClass ) + { + assertException( + "did not catch the expected exception (" + + ( ( i_expectedExceptionClass == null ) ? "none" : i_expectedExceptionClass.getName() ) + + ") while calling " + i_object.getClass().getName() + "." + i_methodName, + i_object, i_methodName, i_methodArgs, i_expectedExceptionClass ); + } + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param i_object is the object to invoke the method on + * @param i_methodName is the name of the method to invoke + * @param i_methodArgs are the arguments to pass to the method + * @param i_argClasses are the classes to assume for the arguments of the methods + * @param i_expectedExceptionClass is the class of the exception to be caught. If this is null, + * it means that <em>no</em> exception must be throw by invoking the method. + */ + public static void assertException( final Object i_object, final String i_methodName, final Class[] i_argClasses, + final Object[] i_methodArgs, final Class i_expectedExceptionClass ) + { + assertException( + "did not catch the expected exception (" + + ( ( i_expectedExceptionClass == null ) ? "none" : i_expectedExceptionClass.getName() ) + + ") while calling " + i_object.getClass().getName() + "." + i_methodName, + i_object, i_methodName, i_argClasses, i_methodArgs, i_expectedExceptionClass ); + } + + // -------------------------------------------------------------------------------------------------------- + public static void assertException( Object i_object, Class _unoInterfaceClass, String i_methodName, Object[] i_methodArgs, + Class i_expectedExceptionClass ) + { + assertException( UnoRuntime.queryInterface( _unoInterfaceClass, i_object ), i_methodName, + i_methodArgs, i_expectedExceptionClass ); + } +} diff --git a/toolkit/qa/complex/toolkit/GridControl.java b/toolkit/qa/complex/toolkit/GridControl.java index 31ac7b56e086..a06a52342417 100755 --- a/toolkit/qa/complex/toolkit/GridControl.java +++ b/toolkit/qa/complex/toolkit/GridControl.java @@ -26,6 +26,11 @@ package complex.toolkit; +import com.sun.star.awt.XControl; +import com.sun.star.awt.XControlContainer; +import com.sun.star.awt.XControlModel; +import com.sun.star.awt.XToolkit; +import com.sun.star.awt.grid.DefaultGridDataModel; import com.sun.star.awt.grid.XGridColumn; import com.sun.star.awt.grid.XGridColumnModel; import com.sun.star.awt.grid.XGridDataModel; @@ -35,10 +40,12 @@ import com.sun.star.beans.Pair; import com.sun.star.beans.XPropertySet; import com.sun.star.container.ContainerEvent; import com.sun.star.container.XContainerListener; +import com.sun.star.container.XNameContainer; import com.sun.star.lang.EventObject; import com.sun.star.lang.IndexOutOfBoundsException; import com.sun.star.lang.XComponent; import com.sun.star.lang.XEventListener; +import com.sun.star.lang.XMultiServiceFactory; import com.sun.star.uno.Exception; import com.sun.star.uno.UnoRuntime; import com.sun.star.uno.XComponentContext; @@ -204,6 +211,14 @@ public class GridControl test.testUpdateRowData(); test.testUpdateRowHeading(); test.cleanup(); + + // a somehwat less straight-forward test: the data model is expected to implicitly increase its column count + // when you add a row which has more columns than currently known + final XMutableGridDataModel dataModel = DefaultGridDataModel.create( m_context ); + dataModel.addRow( 0, new Object[] { 1 } ); + assertEquals( "unexpected column count after adding the most simple row", 1, dataModel.getColumnCount() ); + dataModel.addRow( 1, new Object[] { 1, 2 } ); + assertEquals( "implicit extension of the column count doesn't work", 2, dataModel.getColumnCount() ); } // ----------------------------------------------------------------------------------------------------------------- @@ -387,6 +402,67 @@ public class GridControl } // ----------------------------------------------------------------------------------------------------------------- + @Test + public void testModelViewInteraction() throws Exception + { + final List< Object > disposables = new ArrayList< Object >(); + try + { + // create a siple dialog model/control/peer trinity + final XControlModel dialogModel = createInstance( XControlModel.class, "com.sun.star.awt.UnoControlDialogModel" ); + disposables.add( dialogModel ); + final XPropertySet dialogProps = UnoRuntime.queryInterface( XPropertySet.class, dialogModel ); + dialogProps.setPropertyValue( "Width", 200 ); + dialogProps.setPropertyValue( "Height", 100 ); + dialogProps.setPropertyValue( "Title", "Grid Control Unit Test" ); + final XControl dialogControl = createInstance( XControl.class, "com.sun.star.awt.UnoControlDialog" ); + disposables.add( dialogControl ); + dialogControl.setModel( dialogModel ); + dialogControl.createPeer( createInstance( XToolkit.class, "com.sun.star.awt.Toolkit" ), null ); + + // insert a grid control model + final XMultiServiceFactory controlModelFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class, + dialogModel ); + XPropertySet gridModelProps = UnoRuntime.queryInterface( XPropertySet.class, + controlModelFactory.createInstance( "com.sun.star.awt.grid.UnoControlGridModel" ) ); + disposables.add( gridModelProps ); + gridModelProps.setPropertyValue( "PositionX", 6 ); + gridModelProps.setPropertyValue( "PositionY", 6 ); + gridModelProps.setPropertyValue( "Width", 188 ); + gridModelProps.setPropertyValue( "Height", 88 ); + final XNameContainer modelContainer = UnoRuntime.queryInterface( XNameContainer.class, dialogModel ); + modelContainer.insertByName( "grid", gridModelProps ); + + // check the respective control has been created + final XControlContainer controlContainer = UnoRuntime.queryInterface( XControlContainer.class, dialogControl ); + final XControl gridControl = controlContainer.getControl( "grid" ); + assertNotNull( "no grid control created in the dialog", gridControl ); + + // in the current implementation (not sure this is a good idea at all), the control (more precise: the peer) + // ensures that if there are no columns in the column model, but in the data model, then the column model + // will implicitly have the needed columns added. + // To ensure that clients which rely on this do not break in the future, check this here. + final XMutableGridDataModel dataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, + gridModelProps.getPropertyValue( "GridDataModel" ) ); + assertNotNull( dataModel ); + assertEquals( 0, dataModel.getColumnCount() ); + + final XGridColumnModel columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, + gridModelProps.getPropertyValue( "ColumnModel" ) ); + assertNotNull( columnModel ); + assertEquals( 0, columnModel.getColumnCount() ); + + dataModel.addRow( null, new Object[] { 1, 2, 3 } ); + assertEquals( 3, dataModel.getColumnCount() ); + assertEquals( 3, columnModel.getColumnCount() ); + } + finally + { + impl_dispose( disposables.toArray()); + } + } + + // ----------------------------------------------------------------------------------------------------------------- private int impl_assertInteger( final Object i_object ) { assertTrue( i_object instanceof Integer ); @@ -505,6 +581,12 @@ public class GridControl } // ----------------------------------------------------------------------------------------------------------------- + public <T> T createInstance( Class<T> i_interfaceClass, final String i_serviceIndentifer ) throws Exception + { + return UnoRuntime.queryInterface( i_interfaceClass, createInstance( i_serviceIndentifer ) ); + } + + // ----------------------------------------------------------------------------------------------------------------- private Object createInstance( final String i_serviceName ) throws Exception { Object instance = m_context.getServiceManager().createInstanceWithContext( i_serviceName, m_context ); diff --git a/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java b/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java index e55b2b1bb0ad..c550dd9a047d 100755 --- a/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java +++ b/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java @@ -26,11 +26,13 @@ package complex.toolkit.awtgrid; +import java.lang.reflect.Method; import com.sun.star.awt.grid.GridDataEvent; import com.sun.star.awt.grid.XMutableGridDataModel; import com.sun.star.lang.IllegalArgumentException; import com.sun.star.lang.IndexOutOfBoundsException; import static org.junit.Assert.*; +import static complex.toolkit.Assert.*; /** test for the <code>css.awt.grid.XMutableGridData</code> interface * @@ -49,19 +51,21 @@ public class TMutableGridDataModel /* * tests the XMutableGridDataModel.addRow method */ - public void testAddRow() + public void testAddRow() throws IndexOutOfBoundsException { m_dataModel.addRow( 1, m_rowValues[0] ); GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); + m_listener.reset(); assertEquals( "row insertion: wrong FirstRow (1)", 0, event.FirstRow ); assertEquals( "row insertion: wrong LastRow (1)", 0, event.LastRow ); - m_listener.reset(); + impl_assertRowData( 0 ); m_dataModel.addRow( 2, m_rowValues[1] ); event = m_listener.assertSingleRowInsertionEvent(); + m_listener.reset(); assertEquals( "row insertion: wrong FirstRow (2)", 1, event.FirstRow ); assertEquals( "row insertion: wrong LastRow (2)", 1, event.LastRow ); - m_listener.reset(); + impl_assertRowData( 1 ); } /** @@ -87,6 +91,9 @@ public class TMutableGridDataModel m_rowValues[row][col], m_dataModel.getCellData( col, row ) ); } } + + assertException( "addRows is expected to throw when invoked with different-sized arrays", + m_dataModel, "addRows", new Object[] { new Object[0], new Object[1][2] }, IllegalArgumentException.class ); } /** @@ -112,6 +119,11 @@ public class TMutableGridDataModel m_rowValues[row+1][col], m_dataModel.getCellData( col, row ) ); } } + + assertException( "removeRow silently ignores an invalid index (1)", + m_dataModel, "removeRow", new Object[] { -1 }, IndexOutOfBoundsException.class ); + assertException( "removeRow silently ignores an invalid index (2)", + m_dataModel, "removeRow", new Object[] { m_dataModel.getRowCount() }, IndexOutOfBoundsException.class ); } /** @@ -163,6 +175,16 @@ public class TMutableGridDataModel assertEquals( "data change at (" + col + ", " + row + ") not successful", value, m_dataModel.getCellData( col, row ) ); } + + assertException( "updateCellData silently ignores an invalid index (1)", + m_dataModel, "updateCellData", new Class[] { int.class, int.class, Object.class }, + new Object[] { -1, -1, "text" }, IndexOutOfBoundsException.class ); + assertException( "updateCellData silently ignores an invalid index (2)", + m_dataModel, "updateCellData", new Class[] { int.class, int.class, Object.class }, + new Object[] { 0, m_dataModel.getRowCount(), "text" }, IndexOutOfBoundsException.class ); + assertException( "updateCellData silently ignores an invalid index (3)", + m_dataModel, "updateCellData", new Class[] { int.class, int.class, Object.class }, + new Object[] { m_dataModel.getColumnCount(), 0, "text" }, IndexOutOfBoundsException.class ); } /** @@ -202,6 +224,17 @@ public class TMutableGridDataModel // ensure both the manually updated pre-update data and the post-update data are identical assertArrayEquals( preUpdateValues, postUpdateValues ); + + + assertException( "updateRowData silently ignores an invalid index (1)", + m_dataModel, "updateRowData", new Class[] { int[].class, int.class, Object[].class }, + new Object[] { new int[] { -1 }, 0, new Object[] { "text" } }, IndexOutOfBoundsException.class ); + assertException( "updateRowData silently ignores an invalid index (2)", + m_dataModel, "updateRowData", new Class[] { int[].class, int.class, Object[].class }, + new Object[] { new int[] { 0 }, -1, new Object[] { "" } }, IndexOutOfBoundsException.class ); + assertException( "updateRowData silently ignores different-sized arrays", + m_dataModel, "updateRowData", new Class[] { int[].class, int.class, Object[].class }, + new Object[] { new int[] { 0, 0 }, 0, new Object[] { "" } }, IllegalArgumentException.class ); } /** @@ -225,6 +258,10 @@ public class TMutableGridDataModel final Object[] postUpdateHeadings = impl_getCurrentRowHeadings(); assertArrayEquals( preUpdateHeadings, postUpdateHeadings ); + + assertException( "updateRowHeading silently ignores an invalid index", + m_dataModel, "updateRowHeading", new Class[] { int.class, Object.class }, + new Object[] { -1, "" }, IndexOutOfBoundsException.class ); } public void cleanup() @@ -256,6 +293,14 @@ public class TMutableGridDataModel return headings; } + private void impl_assertRowData( final int i_rowIndex ) throws IndexOutOfBoundsException + { + for ( int i=0; i<m_rowValues[i_rowIndex].length; ++i ) + { + assertEquals( m_rowValues[i_rowIndex][i], m_dataModel.getCellData( i, i_rowIndex ) ); + } + } + private final XMutableGridDataModel m_dataModel; private final GridDataListener m_listener; diff --git a/toolkit/qa/complex/toolkit/makefile.mk b/toolkit/qa/complex/toolkit/makefile.mk index aea14dbfc7f8..e912721739c4 100755 --- a/toolkit/qa/complex/toolkit/makefile.mk +++ b/toolkit/qa/complex/toolkit/makefile.mk @@ -52,6 +52,7 @@ JAVAFILES = \ accessibility/_XAccessibleEventBroadcaster.java \ accessibility/_XAccessibleExtendedComponent.java \ accessibility/_XAccessibleText.java \ + Assert.java \ awtgrid/GridDataListener.java \ awtgrid/TMutableGridDataModel.java \ awtgrid/DummyColumn.java \ |