/* * ATestChartOperations.java of project jchart2d, * base class for visual method invocation test for a * info.monitorenter.gui.chart.Chart2D. * Copyright 2007 (C) Achim Westermann, created on 25.02.2007 18:59:08. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA* * If you modify or optimize the code in a useful way please let me know. * Achim.Westermann@gmx.de * */ package info.monitorenter.gui.chart.test; import info.monitorenter.gui.chart.Chart2D; import info.monitorenter.gui.chart.ITrace2D; import info.monitorenter.gui.chart.dialogs.ModalDialog; import info.monitorenter.gui.chart.traces.Trace2DSimple; import java.awt.Dimension; import java.awt.Point; import java.lang.reflect.Method; import javax.swing.JFrame; import javax.swing.JTextArea; import junit.framework.Assert; import junit.framework.TestCase; /** * Base class for visual method invocation test for a * <code>{@link info.monitorenter.gui.chart.Chart2D}</code>. * <p> * * Test methods should only contain the code to set the test operation they want * to perform (via * <code>{@link #setTestOperation(ATestChartOperations.IChart2DOperation)}</code> * ). * <p> * * @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann</a> * * * @version $Revision: 1.15 $ */ public abstract class ATestChartOperations extends TestCase { /** * Base class for chart operations that manages the name property. * <p> * * @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann</a> * * * @version $Revision: 1.15 $ */ public abstract class AChartOperation implements ATestChartOperations.IChart2DOperation { /** The name of this operation. */ private String m_name; /** * Constructor with the operation's name. * <p> * * @param name * the name of this operation. */ public AChartOperation(final String name) { this.m_name = name; } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#createChartInstance() */ public Chart2D createChartInstance() { return new Chart2D(); } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#createTraces() */ public ITrace2D[] createTraces() { ITrace2D result = new Trace2DSimple(); return new ITrace2D[] {result }; } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#fillTrace(info.monitorenter.gui.chart.ITrace2D) */ public void fillTrace(final ITrace2D trace) { for (int i = 0; i < 101; i++) { trace.addPoint(i, i * (1 + Math.random())); } } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#getName() */ public final String getName() { return this.m_name; } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#postCondition(info.monitorenter.gui.chart.Chart2D, * java.lang.Object) */ public void postCondition(final Chart2D chart, final Object result) throws Exception { // nop } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#preCondition(info.monitorenter.gui.chart.Chart2D) */ public void preCondition(final Chart2D chart) throws Exception { // nop } /** * @see java.lang.Object#toString() */ @Override public String toString() { return this.getName(); } } /** * A chart operation implementation that is based upon reflection. * <p> * * The advantage is that it is generic as it may be used for many different * operations upon a chart. The disadvantages are that it may only perform a * single operation (e.g. no subsequent calls for doing sth. on axis or * traces), costs more time and will not show complilation errors upon * signature changes but only throw exceptions if the desired method is not * found any more. * <p> * * Prefer other implementations for more complex operations to test than a * single call upon the chart. * <p> * * @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann</a> * * * @version $Revision: 1.15 $ */ public abstract class AChartOperationReflectionBased implements ATestChartOperations.IChart2DOperation { /** The operation to test. */ private Method m_operation; /** The arguments for the operation to test. */ private Object[] m_arguments; /** * Creates an operation that will invoke the method of class {@link Chart2D} * specified by the name and the arguments. * <p> * * @param methodName * the name of the method to invoke. * * @param arguments * the arguments for the method to invoke. * * @throws SecurityException * if the method is not accessible. * * @throws NoSuchMethodException * if the method does not exist. */ public AChartOperationReflectionBased(final String methodName, final Object[] arguments) throws SecurityException, NoSuchMethodException { this.m_operation = Chart2D.class.getMethod(methodName, this.toTypeArray(arguments)); this.m_arguments = arguments; } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#action(info.monitorenter.gui.chart.Chart2D) */ public Object action(final Chart2D chart) throws Exception { Object result = this.m_operation.invoke(chart, this.m_arguments); return result; } /** * * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#createChartInstance() */ public Chart2D createChartInstance() { return new Chart2D(); } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#createTraces() */ public ITrace2D[] createTraces() { ITrace2D result = new Trace2DSimple(); long timeOffset = System.currentTimeMillis(); for (int i = 0; i < 101; i++) { result.addPoint(timeOffset + i, i); } return new ITrace2D[] {result }; } /** * @see info.monitorenter.gui.chart.test.ATestChartOperations.IChart2DOperation#getName() */ public String getName() { return this.m_operation.getName(); } /** * @see java.lang.Object#toString() */ @Override public String toString() { return this.getName(); } /** * Internal helper for method lookup. * <p> * * @param args * the argument instances for the method to invoke. * * @return the argument types for the method to invoke. */ private final Class< ? >[] toTypeArray(final Object[] args) { Class< ? >[] result = new Class< ? >[args.length]; for (int i = 0; i < args.length; i++) { result[i] = args[i].getClass(); } return result; } } /** * Encapsulation of an action to perform upon the chart to test. * <p> * * @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann</a> * * @version $Revision: 1.15 $ */ public interface IChart2DOperation { /** * Perform the method on the chart to test. * <p> * * @param chart * the chart to test the action upon. * * @return null or a result of the operation. * * @throws Exception * if sth. goes wrong. */ public Object action(final Chart2D chart) throws Exception; /** * Simply create the proper <code>{@link Chart2D}</code> instance. * <p> * This allows to test subclasses (e.g. * <code>{@link info.monitorenter.gui.chart.ZoomableChart}</code>) too. * <p> * * @return the chart instance to test. */ public Chart2D createChartInstance(); /** * Create the traces here. * <p> * * @return the traces to test. */ public ITrace2D[] createTraces(); /** * Fill the given trace with data points. * <p> * * @param trace * the trace to fill with data points. */ public void fillTrace(ITrace2D trace); /** * Returns the name of the action to perform. * <p> * * @return the name of the action to perform. */ public String getName(); /** * Check any pre condition for the operation to test and throw an exception * to signal a fail. * <p> * * @param chart * the chart the operation was tested on. * * @param result * the result of the operation or null if there is none. * * @throws Exception * if the postCondition was not fulfilled. */ public void postCondition(final Chart2D chart, Object result) throws Exception; /** * Check any pre condition for the operation to test and throw an exception * to signal a fail. * <p> * * @param chart * the chart to invoke the operation on. * * @throws Exception * if the preCondition is not fulfilled. */ public void preCondition(final Chart2D chart) throws Exception; } /** The operation to test for the current test method. */ private IChart2DOperation m_testOperation; /** * Constructor with the test name. * <p> * * @param arg0 * the name of the test. */ public ATestChartOperations(final String arg0) { super(arg0); } /** * Test methods should only contain the code to set the test operation they * want to perform. * <p> * This operation will be invoked in the <code>{@link #tearDown()} </code> * implementation. * <p> * * @param testOperation * the operation to test for the current test method. */ protected void setTestOperation(final ATestChartOperations.IChart2DOperation testOperation) { this.m_testOperation = testOperation; } /** * @see info.monitorenter.gui.chart.test.ATestJChart2D#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); } /** * @see info.monitorenter.gui.chart.test.ATestJChart2D#tearDown() */ @Override protected void tearDown() throws Exception { Assert.assertNotNull( "Test method has to invoke setTestOperation(ATestChartOperations.IChart2DOperation)", this.m_testOperation); // this.m_axisX = this.createAxisX(); // this.m_axisY = this.createAxisY(); ITrace2D[] traces = this.m_testOperation.createTraces(); Chart2D chart = this.m_testOperation.createChartInstance(); for (int i = 0; i < traces.length; i++) { chart.addTrace(traces[i]); this.m_testOperation.fillTrace(traces[i]); } // Assert.assertNotSame(this.m_axisX, this.m_axisY); JFrame frame = new JFrame(); frame.getContentPane().add(chart); // this.m_frame.add(new ChartPanel(this.m_chart)); frame.setSize(400, 600); frame.setLocation(new Point(200, 200)); frame.setVisible(true); Thread.sleep(1000); this.m_testOperation.preCondition(chart); // Modal dialog for announcing the test: JTextArea textArea = new JTextArea(); textArea.setEditable(false); textArea.setText(this.m_testOperation.getName()); ModalDialog dialog = new ModalDialog(frame, "Operation to test...", textArea); dialog.setSize(new Dimension(400, 100)); dialog.showDialog(); boolean failure = false; Object result; if (dialog.isOk()) { result = this.m_testOperation.action(chart); // let tester take a look: try { Thread.sleep(2000); } catch (InterruptedException ie) { // nop } this.m_testOperation.postCondition(chart, result); // Modal dialog after the test for human judgment of success: textArea.setText("Does the result look ok?"); dialog.setTitle("Judge operation " + this.m_testOperation.getName()); dialog.showDialog(); if (!dialog.isOk()) { failure = true; } } frame.setVisible(false); frame.dispose(); super.tearDown(); if (failure) { Assert .fail("Operation test " + this.m_testOperation.getName() + " was judged as a failure. "); } this.m_testOperation = null; super.tearDown(); } }