package com.vaadin.tests.server.component.window; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import org.junit.Assert; import org.junit.Test; import com.vaadin.server.ClientConnector; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinSession; import com.vaadin.tests.util.AlwaysLockedVaadinSession; import com.vaadin.ui.HasComponents.ComponentAttachEvent; import com.vaadin.ui.HasComponents.ComponentDetachEvent; import com.vaadin.ui.Label; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; public class AttachDetachWindowTest { private final VaadinSession testApp = new AlwaysLockedVaadinSession(null); private interface TestContainer { public boolean attachCalled(); public boolean detachCalled(); public TestContent getTestContent(); public VaadinSession getSession(); } private class TestWindow extends Window implements TestContainer { boolean windowAttachCalled = false; boolean windowDetachCalled = false; private final TestContent testContent = new TestContent(); TestWindow() { setContent(testContent); } @Override public void attach() { super.attach(); windowAttachCalled = true; } @Override public void detach() { super.detach(); windowDetachCalled = true; } @Override public boolean attachCalled() { return windowAttachCalled; } @Override public boolean detachCalled() { return windowDetachCalled; } @Override public TestContent getTestContent() { return testContent; } @Override public VaadinSession getSession() { return super.getSession(); } } private class TestContent extends VerticalLayout { boolean contentDetachCalled = false; boolean childDetachCalled = false; boolean contentAttachCalled = false; boolean childAttachCalled = false; private final Label child = new Label() { @Override public void attach() { super.attach(); childAttachCalled = true; } @Override public void detach() { super.detach(); childDetachCalled = true; } }; public TestContent() { addComponent(child); } @Override public void attach() { super.attach(); contentAttachCalled = true; } @Override public void detach() { super.detach(); contentDetachCalled = true; } } private class TestUI extends UI implements TestContainer { boolean rootAttachCalled = false; boolean rootDetachCalled = false; private final TestContent testContent = new TestContent(); public TestUI() { setContent(testContent); } @Override protected void init(VaadinRequest request) { // Do nothing } @Override public boolean attachCalled() { return rootAttachCalled; } @Override public boolean detachCalled() { return rootDetachCalled; } @Override public TestContent getTestContent() { return testContent; } @Override public void attach() { super.attach(); rootAttachCalled = true; } @Override public void detach() { super.detach(); rootDetachCalled = true; } } TestUI main = new TestUI(); TestWindow sub = new TestWindow(); @Test public void addSubWindowBeforeAttachingMainWindow() { assertUnattached(main); assertUnattached(sub); main.addWindow(sub); assertUnattached(main); assertUnattached(sub); // attaching main should recurse to sub main.setSession(testApp); assertAttached(main); assertAttached(sub); } @Test public void addSubWindowAfterAttachingMainWindow() { assertUnattached(main); assertUnattached(sub); main.setSession(testApp); assertAttached(main); assertUnattached(sub); // main is already attached, so attach should be called for sub main.addWindow(sub); assertAttached(main); assertAttached(sub); } @Test public void removeSubWindowBeforeDetachingMainWindow() { main.setSession(testApp); main.addWindow(sub); // sub should be detached when removing from attached main main.removeWindow(sub); assertAttached(main); assertDetached(sub); // main detach should recurse to sub main.setSession(null); assertDetached(main); assertDetached(sub); } @Test public void removeSubWindowAfterDetachingMainWindow() { main.setSession(testApp); main.addWindow(sub); // main detach should recurse to sub main.setSession(null); assertDetached(main); assertDetached(sub); main.removeWindow(sub); assertDetached(main); assertDetached(sub); } @Test public void addWindow_attachEventIsFired() { TestUI ui = new TestUI(); final Window window = new Window(); final boolean[] eventFired = new boolean[1]; ui.addComponentAttachListener((ComponentAttachEvent event) -> { eventFired[0] = event.getAttachedComponent().equals(window); }); ui.addWindow(window); Assert.assertTrue("Attach event is not fired for added window", eventFired[0]); } @Test public void removeWindow_detachEventIsFired() { TestUI ui = new TestUI(); final Window window = new Window(); final boolean[] eventFired = new boolean[1]; ui.addComponentDetachListener((ComponentDetachEvent event) -> { eventFired[0] = event.getDetachedComponent().equals(window); }); ui.addWindow(window); ui.removeWindow(window); Assert.assertTrue("Detach event is not fired for removed window", eventFired[0]); } /** * Asserts that win and its children are attached to testApp and their * attach() methods have been called. */ private void assertAttached(TestContainer win) { TestContent testContent = win.getTestContent(); assertTrue("window attach not called", win.attachCalled()); assertTrue("window content attach not called", testContent.contentAttachCalled); assertTrue("window child attach not called", testContent.childAttachCalled); assertSame("window not attached", win.getSession(), testApp); assertSame("window content not attached", testContent.getUI().getSession(), testApp); assertSame("window children not attached", testContent.child.getUI().getSession(), testApp); } /** * Asserts that win and its children are not attached. */ private void assertUnattached(TestContainer win) { assertSame("window not detached", win.getSession(), null); assertSame("window content not detached", getSession(win.getTestContent()), null); assertSame("window children not detached", getSession(win.getTestContent().child), null); } private VaadinSession getSession(ClientConnector testContainer) { UI ui = testContainer.getUI(); if (ui != null) { return ui.getSession(); } else { return null; } } /** * Asserts that win and its children are unattached and their detach() * methods have been been called. * * @param win */ private void assertDetached(TestContainer win) { assertUnattached(win); assertTrue("window detach not called", win.detachCalled()); assertTrue("window content detach not called", win.getTestContent().contentDetachCalled); assertTrue("window child detach not called", win.getTestContent().childDetachCalled); } }