/* * $Id$ * * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * 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 * */ package org.jdesktop.swingx.decorator; import static org.hamcrest.CoreMatchers.is; import static org.jdesktop.test.matchers.Matchers.property; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import java.awt.Color; import java.beans.PropertyChangeListener; import java.util.logging.Logger; import javax.swing.UIManager; import junit.framework.TestCase; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Contains tests around Highlighter client api for collection components. * <p> * * The common public api: * * <pre><code> * void setHighlighters(Highlighter...) * HighLighter[] getHighlighters() * void addHighlighter(Highlighter) * void removeHighlighter(Highlighter) * updateUI() * </code></pre> * * Subclasses testing concrete implementations must override the createHighlighterClient. * * @author Jeanette Winzenburg */ @RunWith(JUnit4.class) public abstract class AbstractTestHighlighterClient extends TestCase { @SuppressWarnings("unused") private static final Logger LOG = Logger .getLogger(AbstractTestHighlighterClient.class.getName()); // ---- HighlighterClient /** * * @return the concrete HighlighterClient to test */ protected abstract HighlighterClient createHighlighterClient(); /** * Test that the client is messaged on change to a managed Highlighter. */ @Test public void testUpdateUI() { HighlighterClient client = createHighlighterClient(); // force loading of striping colors ColorHighlighter colorHighlighter = (ColorHighlighter) HighlighterFactory.createSimpleStriping(); Color uiColor = UIManager.getColor("UIColorHighlighter.stripingBackground"); if (uiColor == null) { LOG.info("cannot run test - no ui striping color"); return; } assertSame("sanity", uiColor, colorHighlighter.getBackground()); client.addHighlighter(colorHighlighter); Color changedUIColor = Color.RED; UIManager.put("UIColorHighlighter.stripingBackground", changedUIColor); client.updateUI(); try { assertSame("support must update ui color", changedUIColor, colorHighlighter.getBackground()); } finally { UIManager.put("UIColorHighlighter.stripingBackground", uiColor); } } /** * Test assumption is incorrect if the client has internal Highlighters which * are always included! */ @Test public void testSetHighlighters() { HighlighterClient client = createHighlighterClient(); Highlighter[] highlighters = new Highlighter[] {new ColorHighlighter(), new ColorHighlighter()}; client.setHighlighters(highlighters); assertSameContent(highlighters, client.getHighlighters()); } /** * Test property change event on setHighlighters for JXTable. */ @Test public void testSetHighlightersChangeEvent() { HighlighterClient client = createHighlighterClient(); PropertyChangeListener pcl = mock(PropertyChangeListener.class); client.addPropertyChangeListener(pcl); Highlighter[] old = client.getHighlighters(); client.setHighlighters(new ColorHighlighter()); verify(pcl).propertyChange(argThat(is(property("highlighters", old, client.getHighlighters())))); } /** * Sanity: handles empty array. */ @Test public void testSetHighlightersEmptyArray() { HighlighterClient client = createHighlighterClient(); int initialCount = client.getHighlighters().length; client.setHighlighters(new Highlighter[] {}); assertEquals(initialCount, client.getHighlighters().length); } /** * * Test that setting zero highlighter removes all. */ @Test public void testSetHighlightersNoArgument() { HighlighterClient client = createHighlighterClient(); int initialCount = client.getHighlighters().length; client.addHighlighter(new ColorHighlighter()); // sanity assertEquals(initialCount + 1, client.getHighlighters().length); client.setHighlighters(); assertEquals(initialCount + 0, client.getHighlighters().length); } /** * Test strict enforcement of not null allowed in setHighlighters for JXTable. * * Here: null highlighter. */ @Test public void testSetHighlightersNullHighlighter() { try { createHighlighterClient().setHighlighters((Highlighter) null); fail("illegal to call setHighlighters(null)"); } catch (NullPointerException e) { // expected } } /** * Test strict enforcement of not null allowed in setHighlighters for JXTable. * * Here: null array */ @Test public void testSetHighlightersNullArray() { try { createHighlighterClient().setHighlighters((Highlighter[]) null); fail("illegal to call setHighlighters(null)"); } catch (NullPointerException e) { // expected } } /** * Test strict enforcement of not null allowed in setHighlighters for JXTable. * * Here: null array element. */ @Test public void testSetHighlightersArrayNullElement() { try { createHighlighterClient().setHighlighters(new Highlighter[] {null}); fail("illegal to call setHighlighters(null)"); } catch (NullPointerException e) { // expected } } /** * test if removeHighlighter behaves as doc'ed. * */ @Test public void testRemoveHighlighterTable() { HighlighterClient client = createHighlighterClient(); int initialCount = client.getHighlighters().length; // test cope with null client.removeHighlighter(null); Highlighter presetHighlighter = new ColorHighlighter(); client.setHighlighters(presetHighlighter); Highlighter[] highlighters = client.getHighlighters(); // sanity assertEquals(initialCount + 1, highlighters.length); // remove uncontained client.removeHighlighter(new ColorHighlighter()); // assert no change assertSameContent(highlighters, client.getHighlighters()); client.removeHighlighter(presetHighlighter); assertEquals(initialCount, client.getHighlighters().length); } /** * Test property change event on removeHighlighter for JXTable. */ @Test public void testRemoveHighlightersChangeEvent() { HighlighterClient table = createHighlighterClient(); PropertyChangeListener pcl = mock(PropertyChangeListener.class); table.addPropertyChangeListener(pcl); Highlighter highlighter = new ColorHighlighter(); table.setHighlighters(highlighter); Highlighter[] old = table.getHighlighters(); table.removeHighlighter(highlighter); verify(pcl).propertyChange(argThat(is(property("highlighters", old, table.getHighlighters())))); } /** * test if addHighlighter behaves as doc'ed for JXTable. * */ @Test public void testAddHighlighter() { HighlighterClient client = createHighlighterClient(); int initialCount = client.getHighlighters().length; Highlighter presetHighlighter = new ColorHighlighter(); // add the first client.addHighlighter(presetHighlighter); // assert that it is added assertEquals(initialCount + 1, client.getHighlighters().length); assertAsLast(client.getHighlighters(), presetHighlighter); Highlighter highlighter = new ColorHighlighter(); // add the second client.addHighlighter(highlighter); assertEquals(initialCount + 2, client.getHighlighters().length); // assert that it is appended assertAsLast(client.getHighlighters(), highlighter); } /** * Test property change event on addHighlighter for JXTable. */ @Test public void testAddHighlighterChangeEvent() { HighlighterClient table = createHighlighterClient(); PropertyChangeListener pcl = mock(PropertyChangeListener.class); table.addPropertyChangeListener(pcl); Highlighter[] old = table.getHighlighters(); table.addHighlighter(new ColorHighlighter()); verify(pcl).propertyChange(argThat(is(property("highlighters", old, table.getHighlighters())))); } /** * test choking on precondition failure (highlighter must not be null) for JTXTable. * */ @Test public void testAddNullHighlighter() { try { createHighlighterClient().addHighlighter(null); fail("adding a null highlighter must throw NPE"); } catch (NullPointerException e) { // pass - this is what we expect } catch (Exception e) { fail("adding a null highlighter throws exception different " + "from the expected NPE \n" + e); } } /** * Same content in both. * @param highlighters * @param highlighters2 */ private void assertSameContent(Highlighter[] highlighters, Highlighter[] highlighters2) { assertEquals(highlighters.length, highlighters2.length); for (int i = 0; i < highlighters.length; i++) { assertSame("must contain same element", highlighters[i], highlighters2[i]); } } /** * Last in list. * * @param highlighters * @param highlighter */ private void assertAsLast(Highlighter[] highlighters, Highlighter highlighter) { assertTrue("pipeline must not be empty", highlighters.length > 0); assertSame("highlighter must be added as last", highlighter, highlighters[highlighters.length - 1]); } /** * This interface defines the common contract of clients which provide * support for Highlighters. They must * * <ul> * <li> have a bound property "highlighters" denoting a collection of * Highlighters * <li> have methods to modify the collection * <li> update the ui of contained Highlighters on LAF changes * <li> apply the highlighters as appropriate. This implies that it must * listen to highlighter state changes to update itself (or related parties) * accordingly. * </ul> * * The last bullet is a "vague" requirement in that it might vary * considerably across client implementations. While JComponents typically * will invoke a repaint, a non-component might choose to notify some other * listeners. Furthermore, it's not testable, as clients might choose to do * the actual update only if really needed, f.i. not if invisible or if * there are no external listeners. * <p> * */ public static interface HighlighterClient { /** * Sets the <code>Highlighter</code>s to this client, replacing any old settings. * No argument or an empty array removes all <code>Highlighter</code>s. <p> * * This is a bound property. * * @param highlighters zero or more not null highlighters to use for renderer decoration. * @throws NullPointerException if array is null or array contains null values. * * @see #getHighlighters() * @see #addHighlighter(Highlighter) * @see #removeHighlighter(Highlighter) * */ void setHighlighters(Highlighter... highlighters); /** * Returns the <code>Highlighter</code>s used by this client. * Maybe empty, but guarantees to be never null. * * @return the Highlighters used by this table, guaranteed to never null. * * @see #setHighlighters(Highlighter[]) */ Highlighter[] getHighlighters(); /** * Appends a <code>Highlighter</code> to the end of the list of used * <code>Highlighter</code>s. The argument must not be null. * <p> * * @param highlighter the <code>Highlighter</code> to add, must not be null. * @throws NullPointerException if <code>Highlighter</code> is null. * * @see #removeHighlighter(Highlighter) * @see #setHighlighters(Highlighter[]) */ void addHighlighter(Highlighter highlighter); /** * Removes the given <code>Highlighter</code>. Does nothing if the * <code>Highlighter</code> is not contained. * * @param highlighter the <code>Highlighter</code> to remove. * * @see #addHighlighter(Highlighter) * @see #setHighlighters(Highlighter...) */ void removeHighlighter(Highlighter highlighter); /** * Updates contained Highlighters on LAF changes. */ void updateUI(); /** * Adds a PropertyChangeListener which will be notified on changes of the * "highlighters" property. * * @param l the listener to add. */ void addPropertyChangeListener(PropertyChangeListener l); /** * Removes the <code>PropertyChangeListener</code>. Does nothing if the * listener is not contained. * * @param l the listener to remove. */ void removePropertyChangeListener(PropertyChangeListener l); } }