package org.leumasjaffe.recipe.view; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize; import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import javax.swing.JTextField; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.leumasjaffe.recipe.view.AutoGrowPanel.ChildComponent; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) class AutoGrowPanelTest extends SwingTestCase { @SuppressWarnings("serial") private static class MockComponent extends JTextField implements ChildComponent { public MockComponent() { } public MockComponent(String s) { super(s); } @Override public void addGrowShrinkListener(DocumentListener dl) { super.getDocument().addDocumentListener(dl); } @Override public void removeGrowShrinkListener(DocumentListener dl) { super.getDocument().removeDocumentListener(dl); } } @Mock Consumer callback; List internal = new ArrayList<>(); @Spy List shared = new ArrayList<>(); private MockComponent mocked() { final MockComponent mock = spy(new MockComponent()); internal.add(mock); return mock; } private AutoGrowPanel create(MockComponent... mocks) { shared.addAll(Arrays.asList(mocks)); final AutoGrowPanel rval = new AutoGrowPanel<>(this::mocked, m -> m); rval.setModel(shared); return rval; } @Test void testAlwaysHasAtLeastOneComponent() { AutoGrowPanel panel = new AutoGrowPanel<>(this::mocked, m -> m); assertThat(panel.getComponents(), arrayWithSize(1)); } @Test void testInitialComponentAssignedFirstPosition() { @SuppressWarnings("unused") AutoGrowPanel panel = new AutoGrowPanel<>(this::mocked, m -> m); verify(internal.get(0)).setListPosition(0); } @Test void testSetModelCallsListPositionEvenIfNoChange() { AutoGrowPanel panel = create(); assertThat(panel.getComponents(), arrayWithSize(1)); verify(internal.get(0), times(2)).setListPosition(0); } @Test void testCreatesGivenNumberOfChildrenPlusOne() { AutoGrowPanel panel = create(mocked(), mocked()); assertThat(panel.getComponents(), arrayWithSize(3)); verify(shared, never()).add(any()); } @Test void testResetsListPositionAfterSettingModel() { @SuppressWarnings("unused") AutoGrowPanel panel = create(mocked(), mocked()); // Last element because my helper function pre-installs into the internal list verify(internal.get(2)).setListPosition(0); verify(internal.get(2)).setListPosition(2); } @Test void testEnteringContentTriggersNewRow() { AutoGrowPanel panel = create(); internal.get(0).setText("A"); assertThat(panel.getComponents(), arrayWithSize(2)); internal.get(1).setText("B"); assertThat(panel.getComponents(), arrayWithSize(3)); verify(shared, times(2)).add(any()); } @Test void testEnteringContentAssignsCorrectListPosition() { @SuppressWarnings("unused") AutoGrowPanel panel = create(); internal.get(0).setText("A"); verify(internal.get(1)).setListPosition(1); } @Test void testEnteringEmptyContentDoesNotTrigger() { AutoGrowPanel panel = create(); getTestFrame().add(panel); internal.get(0).setText(""); assertThat(panel.getComponents(), arrayWithSize(1)); verify(shared, never()).add(any()); verify(shared, never()).remove(anyInt()); } @Test void testEmptyingContentClearsPanel() { final MockComponent mock = spy(new MockComponent("A")); AutoGrowPanel panel = create(mock); getTestFrame().add(panel); mock.setText(""); assertThat(panel.getComponents(), arrayWithSize(1)); verify(shared, times(1)).remove(0); } @Test void testEmptyingContentAdjustsAllPositions() { final MockComponent mock = spy(new MockComponent("A")); @SuppressWarnings("unused") AutoGrowPanel panel = create(mock); mock.setText(""); verify(internal.get(0), times(2)).setListPosition(0); } @Test void testRemovingSomeContentDoesntClear() throws BadLocationException { final MockComponent mock = spy(new MockComponent("AB")); AutoGrowPanel panel = create(mock); getTestFrame().add(panel); mock.getDocument().remove(0, 1); assertThat(panel.getComponents(), arrayWithSize(2)); verify(shared, never()).remove(anyInt()); } @Test void testChangingTextDoesNotDeleteRow() throws BadLocationException { final MockComponent mock = spy(new MockComponent("A")); AutoGrowPanel panel = create(mock); getTestFrame().add(panel); mock.getDocument().insertString(0, "B", null); assertThat(panel.getComponents(), arrayWithSize(2)); verify(shared, never()).remove(anyInt()); } @Test void testCanInstallNotificationCallbackForAddsAndDeletes() { AutoGrowPanel panel = create(); panel.setModel(shared, callback); getTestFrame().add(panel); verify(callback, never()).accept(anyBoolean()); internal.get(0).setText("A"); verify(callback).accept(true); internal.get(0).setText(""); verify(callback).accept(false); } }