package org.peerbox.presenter; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; import java.io.IOException; import java.lang.reflect.Field; import javafx.collections.ObservableList; import javafx.fxml.FXMLLoader; import javafx.scene.Node; import javafx.scene.control.Label; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.peerbox.guice.IFxmlLoaderProvider; import org.peerbox.helper.JavaFXThreadingRule; public class NavigationServiceTest { @Rule public JavaFXThreadingRule jfxRule = new JavaFXThreadingRule(); /** * Controller instance of the view */ @Mock private INavigatable controller; /** * Guice loader, does not do DI in this test. */ @Mock private IFxmlLoaderProvider fxmlLoaderProvider; /** * FXML loader, does not actually load .fxml files */ @Mock private FXMLLoader fxmlLoader; /** * Navigation service under test */ private NavigationService navigationService; /** * The pages to load for navigation tests */ private Label[] elements; @Before public void setupNavigationService() { /* required due to @Mock annotation */ MockitoAnnotations.initMocks(this); /* create some ui elements */ createPages(); try { /* mock the two methods required for navigation: create(.) and load() */ when(fxmlLoaderProvider.create(anyString())).thenReturn(fxmlLoader); when(fxmlLoader.load()).thenReturn(elements[0], elements[1], elements[2], elements[3]); } catch (IOException e) { /* should not happen as we do not actually load the fxml files */ e.printStackTrace(); } /* initialize the navigation services using the mocks */ navigationService = new NavigationService(fxmlLoaderProvider); navigationService.setNavigationController(controller); } /** * Creates some dummy UI elements to use while testing navigation * Dummy elements need to be of type Node */ private void createPages() { elements = new Label[] { new Label("testpage1.fxml"), new Label("testpage2.fxml"), new Label("testpage3.fxml"), new Label("testpage4.fxml") }; } /** * Cleanup after testing */ @After public void destroyNavigationService() { controller = null; fxmlLoaderProvider = null; fxmlLoader = null; navigationService = null; } @Test(expected = IllegalArgumentException.class) public void testNavigationServiceNull() { new NavigationService(null); } @Test public void testCreateLoader() throws IOException { final String page = "/testpage1.fxml"; navigationService.createLoader(page); Mockito.verify(fxmlLoaderProvider, Mockito.times(1)).create(page); } @Test public void testNavigate() throws IOException { ObservableList<Node> pages = getPages(); assertNotNull(pages); /* first page */ String page_1 = "/testpage1.fxml"; navigationService.navigate(page_1); Mockito.verify(fxmlLoaderProvider, Mockito.times(1)).create(page_1); Mockito.verify(fxmlLoader, Mockito.times(1)).load(); Mockito.verify(controller, Mockito.times(1)).setContent(elements[0]); assertTrue(pages.size() == 1); assertEquals(pages.get(0), elements[0]); /* second page */ String page_2 = "/testpage2.fxml"; navigationService.navigate(page_2); Mockito.verify(fxmlLoaderProvider, Mockito.times(1)).create(page_2); Mockito.verify(fxmlLoader, Mockito.times(2)).load(); Mockito.verify(controller, Mockito.times(1)).setContent(elements[1]); assertTrue(pages.size() == 2); assertEquals(pages.get(0), elements[0]); assertEquals(pages.get(1), elements[1]); /* third page */ String page_3 = "/testpage3.fxml"; navigationService.navigate(page_3); Mockito.verify(fxmlLoaderProvider, Mockito.times(1)).create(page_3); Mockito.verify(fxmlLoader, Mockito.times(3)).load(); Mockito.verify(controller, Mockito.times(1)).setContent(elements[2]); assertTrue(pages.size() == 3); assertEquals(pages.get(0), elements[0]); assertEquals(pages.get(1), elements[1]); assertEquals(pages.get(2), elements[2]); } /** * Gives access to the private pages list of the service using reflection * @return the pages list of the navigation service */ @SuppressWarnings("unchecked") private ObservableList<Node> getPages() { ObservableList<Node> pages = null; try { Class<?> ns = navigationService.getClass(); Field pagesField = ns.getDeclaredField("pages"); pagesField.setAccessible(true); pages = (ObservableList<Node>) pagesField.get(navigationService); } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { e.printStackTrace(); pages = null; } return pages; } @Test public void testNavigateBack() { ObservableList<Node> pages = getPages(); assertNotNull(pages); String page_1 = "/testpage1.fxml"; navigationService.navigate(page_1); String page_2 = "/testpage2.fxml"; navigationService.navigate(page_2); String page_3 = "/testpage3.fxml"; navigationService.navigate(page_3); /* correct order after loading is checked by other test case */ /* now navigate back */ navigationService.navigateBack(); assertTrue(pages.size() == 2); assertEquals(pages.get(0), elements[0]); assertEquals(pages.get(1), elements[1]); navigationService.navigateBack(); assertTrue(pages.size() == 1); assertEquals(pages.get(0), elements[0]); assertFalse(navigationService.canNavigateBack()); } @Test public void testCanNavigateBack() { assertFalse(navigationService.canNavigateBack()); navigationService.navigate("/testpage1.fxml"); assertFalse(navigationService.canNavigateBack()); navigationService.navigate("/testpage2.fxml"); assertTrue(navigationService.canNavigateBack()); navigationService.navigateBack(); assertFalse(navigationService.canNavigateBack()); } @Test(expected = IllegalStateException.class) public void testNavigationErrorOnePage() { assertFalse(navigationService.canNavigateBack()); navigationService.navigate("/testpage1.fxml"); assertFalse(navigationService.canNavigateBack()); navigationService.navigateBack(); /* throws IllegalStateException */ } @Test(expected = IllegalStateException.class) public void testNavigationErrorNoPage() { assertFalse(navigationService.canNavigateBack()); navigationService.navigateBack(); /* throws IllegalStateException */ } @Test public void testClearPages() { navigationService.navigate("/testpage1.fxml"); navigationService.navigate("/testpage2.fxml"); navigationService.navigate("/testpage3.fxml"); ObservableList<Node> pages = getPages(); assertTrue(pages.size() == 3); navigationService.clearPages(); assertTrue(pages.size() == 0); } }