Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

NavigatorTest.java 43KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.tests.server.navigator;
  17. import static org.junit.Assert.assertEquals;
  18. import static org.junit.Assert.assertFalse;
  19. import static org.junit.Assert.assertNotNull;
  20. import static org.junit.Assert.assertNull;
  21. import static org.junit.Assert.assertSame;
  22. import static org.junit.Assert.assertTrue;
  23. import static org.junit.Assert.fail;
  24. import java.util.LinkedList;
  25. import java.util.Map;
  26. import java.util.Map.Entry;
  27. import java.util.concurrent.atomic.AtomicInteger;
  28. import java.util.concurrent.atomic.AtomicReference;
  29. import org.easymock.EasyMock;
  30. import org.easymock.IArgumentMatcher;
  31. import org.easymock.IMocksControl;
  32. import org.junit.Test;
  33. import com.vaadin.navigator.NavigationStateManager;
  34. import com.vaadin.navigator.Navigator;
  35. import com.vaadin.navigator.PushStateNavigation;
  36. import com.vaadin.navigator.View;
  37. import com.vaadin.navigator.ViewBeforeLeaveEvent;
  38. import com.vaadin.navigator.ViewChangeListener;
  39. import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
  40. import com.vaadin.navigator.ViewDisplay;
  41. import com.vaadin.navigator.ViewProvider;
  42. import com.vaadin.server.Page;
  43. import com.vaadin.server.VaadinRequest;
  44. import com.vaadin.shared.Registration;
  45. import com.vaadin.shared.ui.ui.PageState;
  46. import com.vaadin.tests.server.navigator.ClassBasedViewProviderTest.TestView2;
  47. import com.vaadin.ui.Component;
  48. import com.vaadin.ui.HorizontalLayout;
  49. import com.vaadin.ui.Label;
  50. import com.vaadin.ui.UI;
  51. import com.vaadin.ui.VerticalLayout;
  52. public class NavigatorTest {
  53. private final class TestNavigationStateManager
  54. implements NavigationStateManager {
  55. private String state;
  56. @Override
  57. public void setState(String state) {
  58. this.state = state;
  59. }
  60. @Override
  61. public void setNavigator(Navigator navigator) {
  62. }
  63. @Override
  64. public String getState() {
  65. return state;
  66. }
  67. }
  68. // TODO test internal parameters (and absence of them)
  69. // TODO test listeners blocking navigation, multiple listeners
  70. public static class NullDisplay implements ViewDisplay {
  71. @Override
  72. public void showView(View view) {
  73. // do nothing
  74. }
  75. }
  76. public static class NullFragmentManager implements NavigationStateManager {
  77. @Override
  78. public String getState() {
  79. return null;
  80. }
  81. @Override
  82. public void setState(String fragment) {
  83. // do nothing
  84. }
  85. @Override
  86. public void setNavigator(Navigator navigator) {
  87. // do nothing
  88. }
  89. }
  90. public static class TestDisplay implements ViewDisplay {
  91. private View currentView;
  92. @Override
  93. public void showView(View view) {
  94. currentView = view;
  95. }
  96. public View getCurrentView() {
  97. return currentView;
  98. }
  99. }
  100. public static class TestNavigator extends Navigator {
  101. public TestNavigator() {
  102. super(createMockUI(), new NullFragmentManager(), new TestDisplay());
  103. }
  104. public TestNavigator(UI ui) {
  105. super(ui, EasyMock.createMock(ViewDisplay.class));
  106. }
  107. public View getView(String viewAndParameters) {
  108. try {
  109. navigateTo(viewAndParameters);
  110. } catch (IllegalArgumentException e) {
  111. // ignore
  112. }
  113. return ((TestDisplay) getDisplay()).getCurrentView();
  114. }
  115. @Override
  116. protected NavigationStateManager getStateManager() {
  117. return super.getStateManager();
  118. }
  119. }
  120. public static class TestNavigatorWithFragments extends Navigator {
  121. public TestNavigatorWithFragments() {
  122. super(createMockUI(), new NullFragmentManager(), new TestDisplay());
  123. }
  124. public TestNavigatorWithFragments(UI ui) {
  125. super(ui, new UriFragmentManager(ui.getPage()),
  126. EasyMock.createMock(ViewDisplay.class));
  127. }
  128. public View getView(String viewAndParameters) {
  129. try {
  130. navigateTo(viewAndParameters);
  131. } catch (IllegalArgumentException e) {
  132. // ignore
  133. }
  134. return ((TestDisplay) getDisplay()).getCurrentView();
  135. }
  136. @Override
  137. protected NavigationStateManager getStateManager() {
  138. return super.getStateManager();
  139. }
  140. }
  141. public static class ViewChangeTestListener implements ViewChangeListener {
  142. private final LinkedList<ViewChangeEvent> referenceEvents = new LinkedList<>();
  143. private final LinkedList<Boolean> referenceIsCheck = new LinkedList<>();
  144. private final LinkedList<Boolean> checkReturnValues = new LinkedList<>();
  145. public void addExpectedIsViewChangeAllowed(ViewChangeEvent event,
  146. boolean returnValue) {
  147. referenceIsCheck.add(true);
  148. referenceEvents.add(event);
  149. checkReturnValues.add(returnValue);
  150. }
  151. public void addExpectedNavigatorViewChange(ViewChangeEvent event) {
  152. referenceIsCheck.add(false);
  153. referenceEvents.add(event);
  154. }
  155. public boolean isReady() {
  156. return referenceEvents.isEmpty();
  157. }
  158. public boolean equalsReferenceEvent(ViewChangeEvent event,
  159. ViewChangeEvent reference) {
  160. if (event == null) {
  161. return false;
  162. }
  163. if (reference.getNavigator() != event.getNavigator()) {
  164. return false;
  165. }
  166. if (reference.getOldView() != event.getOldView()) {
  167. return false;
  168. }
  169. if (reference.getNewView() != event.getNewView()) {
  170. return false;
  171. }
  172. if (!stringEquals(reference.getViewName(), event.getViewName())) {
  173. return false;
  174. }
  175. if (!stringEquals(reference.getParameters(),
  176. event.getParameters())) {
  177. return false;
  178. }
  179. return true;
  180. }
  181. private static boolean stringEquals(String string1, String string2) {
  182. if (string1 == null) {
  183. return string2 == null;
  184. } else {
  185. return string1.equals(string2);
  186. }
  187. }
  188. @Override
  189. public boolean beforeViewChange(ViewChangeEvent event) {
  190. if (referenceEvents.isEmpty()) {
  191. fail("Unexpected call to beforeViewChange()");
  192. }
  193. ViewChangeEvent reference = referenceEvents.remove();
  194. Boolean isCheck = referenceIsCheck.remove();
  195. if (!isCheck) {
  196. fail("Expected afterViewChange(), received beforeViewChange()");
  197. }
  198. // here to make sure exactly the correct values are removed from
  199. // each queue
  200. Boolean returnValue = checkReturnValues.remove();
  201. if (!equalsReferenceEvent(event, reference)) {
  202. fail("View change event does not match reference event");
  203. }
  204. return returnValue;
  205. }
  206. @Override
  207. public void afterViewChange(ViewChangeEvent event) {
  208. if (referenceEvents.isEmpty()) {
  209. fail("Unexpected call to afterViewChange()");
  210. }
  211. ViewChangeEvent reference = referenceEvents.remove();
  212. Boolean isCheck = referenceIsCheck.remove();
  213. if (isCheck) {
  214. fail("Expected beforeViewChange(), received afterViewChange()");
  215. }
  216. if (!equalsReferenceEvent(event, reference)) {
  217. fail("View change event does not match reference event");
  218. }
  219. }
  220. }
  221. private static class TestUI extends UI {
  222. TestUI(Page page) {
  223. this.page = page;
  224. }
  225. @Override
  226. protected void init(VaadinRequest request) {
  227. }
  228. @Override
  229. public Page getPage() {
  230. return page;
  231. }
  232. private final Page page;
  233. }
  234. @PushStateNavigation
  235. private static class TestPushStateUI extends TestUI {
  236. TestPushStateUI(Page page) {
  237. super(page);
  238. }
  239. }
  240. private static class TestPage extends Page {
  241. public TestPage() {
  242. super(null, null);
  243. }
  244. @Override
  245. public Registration addPopStateListener(PopStateListener listener) {
  246. addPopstateCalled = true;
  247. return () -> removePopstateCalled = true;
  248. }
  249. boolean addPopstateCalled() {
  250. return addPopstateCalled;
  251. }
  252. boolean removePopstateCalled() {
  253. return removePopstateCalled;
  254. }
  255. private boolean addPopstateCalled;
  256. private boolean removePopstateCalled;
  257. }
  258. private static class TestPageWithUriFragments extends Page {
  259. public TestPageWithUriFragments() {
  260. super(null, null);
  261. }
  262. @Override
  263. public Registration addUriFragmentChangedListener(
  264. UriFragmentChangedListener listener) {
  265. addUriFragmentCalled = true;
  266. return () -> removeUriFragmentCalled = true;
  267. }
  268. @Override
  269. public void removeUriFragmentChangedListener(
  270. UriFragmentChangedListener listener) {
  271. removeUriFragmentCalled = true;
  272. }
  273. boolean addUriFragmentCalled() {
  274. return addUriFragmentCalled;
  275. }
  276. boolean removeUriFragmentCalled() {
  277. return removeUriFragmentCalled;
  278. }
  279. private boolean addUriFragmentCalled;
  280. private boolean removeUriFragmentCalled;
  281. }
  282. public static ViewChangeEvent eventParametersEqual(final String expected) {
  283. EasyMock.reportMatcher(new IArgumentMatcher() {
  284. @Override
  285. public void appendTo(StringBuffer buffer) {
  286. buffer.append("paramsIs(\"").append(expected).append("\")");
  287. }
  288. @Override
  289. public boolean matches(Object actual) {
  290. return actual instanceof ViewChangeEvent && expected
  291. .equals(((ViewChangeEvent) actual).getParameters());
  292. }
  293. });
  294. return null;
  295. }
  296. private static UI createMockUI() {
  297. UI ui = EasyMock.createMock(UI.class);
  298. ui.setNavigator(EasyMock.anyObject(Navigator.class));
  299. EasyMock.replay(ui);
  300. return ui;
  301. }
  302. private static Navigator createNavigator(NavigationStateManager manager,
  303. ViewDisplay display) {
  304. return new Navigator(createMockUI(), manager, display);
  305. }
  306. @Test
  307. public void testDestroy_unsetNavigatorInUIAndUriFragmentManager() {
  308. TestPageWithUriFragments page = new TestPageWithUriFragments();
  309. UI ui = new TestUI(page);
  310. TestNavigatorWithFragments navigator = new TestNavigatorWithFragments(
  311. ui);
  312. assertTrue("Add URI fragment Page method has not been called",
  313. page.addUriFragmentCalled());
  314. assertFalse("Unexpected remove URI fragment Page method call",
  315. page.removeUriFragmentCalled());
  316. assertNotNull("Navigator is null in UI", ui.getNavigator());
  317. navigator.destroy();
  318. assertTrue(
  319. "Remove URI fragment Page method has not been called after destroy",
  320. page.removeUriFragmentCalled());
  321. assertNull("Navigator is not null in UI after destroy",
  322. ui.getNavigator());
  323. try {
  324. page.setUriFragment("foobar", true); // This should throw
  325. fail("Expected null pointer exception after call uriFragmentChanged "
  326. + "for destroyed navigator");
  327. } catch (NullPointerException e) {
  328. // All ok.
  329. }
  330. }
  331. @Test
  332. public void testDestroy_unsetNavigatorInUIAndPopstateManager() {
  333. TestPage page = new TestPage();
  334. UI ui = new TestPushStateUI(page);
  335. TestNavigator navigator = new TestNavigator(ui);
  336. assertTrue("Add URI fragment Page method has not been called",
  337. page.addPopstateCalled());
  338. assertFalse("Unexpected remove URI fragment Page method call",
  339. page.removePopstateCalled());
  340. assertNotNull("Navigator is null in UI", ui.getNavigator());
  341. navigator.destroy();
  342. assertTrue(
  343. "Remove URI fragment Page method has not been called after destroy",
  344. page.removePopstateCalled());
  345. assertNull("Navigator is not null in UI after destroy",
  346. ui.getNavigator());
  347. try {
  348. page.updateLocation("http://server/path/info", true, true);
  349. fail("Expected null pointer exception after call uriFragmentChanged "
  350. + "for destroyed navigator");
  351. } catch (NullPointerException e) {
  352. // All ok.
  353. }
  354. }
  355. @Test
  356. public void testBasicNavigation() {
  357. IMocksControl control = EasyMock.createControl();
  358. NavigationStateManager manager = control
  359. .createMock(NavigationStateManager.class);
  360. ViewDisplay display = control.createMock(ViewDisplay.class);
  361. ViewProvider provider = control.createMock(ViewProvider.class);
  362. TestView view1 = new TestView();
  363. TestView view2 = new TestView();
  364. // prepare mocks: what to expect
  365. manager.setNavigator(EasyMock.anyObject(Navigator.class));
  366. EasyMock.expect(provider.getViewName("test1")).andReturn("test1")
  367. .times(2);
  368. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  369. EasyMock.expect(manager.getState()).andReturn("");
  370. display.showView(view1);
  371. manager.setState("test1");
  372. EasyMock.expect(manager.getState()).andReturn("test1");
  373. EasyMock.expect(provider.getViewName("test2/")).andReturn("test2")
  374. .times(2);
  375. EasyMock.expect(provider.getView("test2")).andReturn(view2);
  376. EasyMock.expect(manager.getState()).andReturn("test1");
  377. display.showView(view2);
  378. manager.setState("test2");
  379. EasyMock.expect(manager.getState()).andReturn("test2");
  380. EasyMock.expect(provider.getViewName("test1/params")).andReturn("test1")
  381. .times(2);
  382. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  383. EasyMock.expect(manager.getState()).andReturn("test2");
  384. display.showView(view1);
  385. manager.setState("test1/params");
  386. EasyMock.expect(manager.getState()).andReturn("test1/params");
  387. control.replay();
  388. // create and test navigator
  389. Navigator navigator = createNavigator(manager, display);
  390. navigator.addProvider(provider);
  391. navigator.navigateTo("test1");
  392. assertEquals("test1", navigator.getState());
  393. assertEquals("", view1.getParams());
  394. navigator.navigateTo("test2/");
  395. assertEquals("test2", navigator.getState());
  396. assertEquals("", view2.getParams());
  397. navigator.navigateTo("test1/params");
  398. assertEquals("test1/params", navigator.getState());
  399. assertEquals("params", view1.getParams());
  400. }
  401. public static class TestView implements View {
  402. private String params;
  403. @Override
  404. public void enter(ViewChangeEvent event) {
  405. params = event.getParameters();
  406. }
  407. public String getParams() {
  408. return params;
  409. }
  410. }
  411. @Test
  412. public void testMainView() {
  413. IMocksControl control = EasyMock.createControl();
  414. NavigationStateManager manager = control
  415. .createMock(NavigationStateManager.class);
  416. ViewDisplay display = control.createMock(ViewDisplay.class);
  417. ViewProvider provider = control.createMock(ViewProvider.class);
  418. TestView view1 = new TestView();
  419. TestView view2 = new TestView();
  420. // prepare mocks: what to expect
  421. manager.setNavigator(EasyMock.anyObject(Navigator.class));
  422. EasyMock.expect(provider.getViewName("test2")).andReturn("test2")
  423. .times(2);
  424. EasyMock.expect(provider.getView("test2")).andReturn(view2);
  425. EasyMock.expect(manager.getState()).andReturn("view1");
  426. display.showView(view2);
  427. manager.setState("test2");
  428. EasyMock.expect(provider.getViewName("")).andReturn("test1").times(2);
  429. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  430. EasyMock.expect(manager.getState()).andReturn("");
  431. display.showView(view1);
  432. manager.setState("test1");
  433. EasyMock.expect(provider.getViewName("test1/params")).andReturn("test1")
  434. .times(2);
  435. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  436. EasyMock.expect(manager.getState()).andReturn("test2");
  437. display.showView(view1);
  438. manager.setState("test1/params");
  439. control.replay();
  440. // create and test navigator
  441. Navigator navigator = createNavigator(manager, display);
  442. navigator.addProvider(provider);
  443. navigator.navigateTo("test2");
  444. assertEquals("", view2.getParams());
  445. assertEquals(null, view1.getParams());
  446. navigator.navigateTo("");
  447. assertEquals("", view1.getParams());
  448. navigator.navigateTo("test1/params");
  449. assertEquals("params", view1.getParams());
  450. }
  451. @Test
  452. public void testListeners() {
  453. IMocksControl control = EasyMock.createControl();
  454. NavigationStateManager manager = control
  455. .createMock(NavigationStateManager.class);
  456. ViewDisplay display = control.createMock(ViewDisplay.class);
  457. ViewProvider provider = control.createMock(ViewProvider.class);
  458. TestView view1 = new TestView();
  459. TestView view2 = new TestView();
  460. ViewChangeTestListener listener = new ViewChangeTestListener();
  461. // create navigator to test
  462. Navigator navigator = createNavigator(manager, display);
  463. // prepare mocks: what to expect
  464. EasyMock.expect(provider.getViewName("test1")).andReturn("test1")
  465. .times(2);
  466. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  467. ViewChangeEvent event1 = new ViewChangeEvent(navigator, null, view1,
  468. "test1", "");
  469. listener.addExpectedIsViewChangeAllowed(event1, true);
  470. EasyMock.expect(manager.getState()).andReturn("");
  471. display.showView(view1);
  472. manager.setState("test1");
  473. listener.addExpectedNavigatorViewChange(event1);
  474. EasyMock.expect(provider.getViewName("test2")).andReturn("test2")
  475. .times(2);
  476. EasyMock.expect(provider.getView("test2")).andReturn(view2);
  477. ViewChangeEvent event2 = new ViewChangeEvent(navigator, view1, view2,
  478. "test2", "");
  479. listener.addExpectedIsViewChangeAllowed(event2, true);
  480. EasyMock.expect(manager.getState()).andReturn("test1");
  481. display.showView(view2);
  482. manager.setState("test2");
  483. listener.addExpectedNavigatorViewChange(event2);
  484. control.replay();
  485. // test navigator
  486. navigator.addProvider(provider);
  487. navigator.addViewChangeListener(listener);
  488. navigator.navigateTo("test1");
  489. navigator.navigateTo("test2");
  490. if (!listener.isReady()) {
  491. fail("Missing listener calls");
  492. }
  493. }
  494. @Test
  495. public void testComponentContainerViewDisplay() {
  496. class TestView extends VerticalLayout implements View {
  497. @Override
  498. public void enter(ViewChangeEvent event) {
  499. }
  500. }
  501. TestView tv1 = new TestView();
  502. TestView tv2 = new TestView();
  503. VerticalLayout container = new VerticalLayout();
  504. ViewDisplay display = new Navigator.ComponentContainerViewDisplay(
  505. container);
  506. Navigator navigator = createNavigator(new NullFragmentManager(),
  507. display);
  508. navigator.addView("tv1", tv1);
  509. navigator.addView("tv2", tv2);
  510. navigator.navigateTo("tv1");
  511. assertSame(tv1, container.getComponent(0));
  512. assertEquals(1, container.getComponentCount());
  513. navigator.navigateTo("tv2");
  514. assertSame(tv2, container.getComponent(0));
  515. assertEquals(1, container.getComponentCount());
  516. }
  517. @Test
  518. public void testBlockNavigation() {
  519. IMocksControl control = EasyMock.createControl();
  520. NavigationStateManager manager = control
  521. .createMock(NavigationStateManager.class);
  522. ViewDisplay display = control.createMock(ViewDisplay.class);
  523. ViewProvider provider = control.createMock(ViewProvider.class);
  524. TestView view1 = new TestView();
  525. TestView view2 = new TestView();
  526. ViewChangeTestListener listener1 = new ViewChangeTestListener();
  527. ViewChangeTestListener listener2 = new ViewChangeTestListener();
  528. Navigator navigator = createNavigator(manager, display);
  529. // prepare mocks: what to expect
  530. // first listener blocks first view change
  531. EasyMock.expect(provider.getViewName("test1")).andReturn("test1")
  532. .times(2);
  533. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  534. EasyMock.expect(manager.getState()).andReturn("");
  535. ViewChangeEvent event1 = new ViewChangeEvent(navigator, null, view1,
  536. "test1", "");
  537. listener1.addExpectedIsViewChangeAllowed(event1, false);
  538. // second listener blocks second view change
  539. EasyMock.expect(provider.getViewName("test1/test")).andReturn("test1")
  540. .times(2);
  541. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  542. EasyMock.expect(manager.getState()).andReturn("");
  543. ViewChangeEvent event2 = new ViewChangeEvent(navigator, null, view1,
  544. "test1", "test");
  545. listener1.addExpectedIsViewChangeAllowed(event2, true);
  546. listener2.addExpectedIsViewChangeAllowed(event2, false);
  547. // both listeners allow view change
  548. EasyMock.expect(provider.getViewName("test1/bar")).andReturn("test1")
  549. .times(2);
  550. EasyMock.expect(provider.getView("test1")).andReturn(view1);
  551. EasyMock.expect(manager.getState()).andReturn("");
  552. ViewChangeEvent event3 = new ViewChangeEvent(navigator, null, view1,
  553. "test1", "bar");
  554. listener1.addExpectedIsViewChangeAllowed(event3, true);
  555. listener2.addExpectedIsViewChangeAllowed(event3, true);
  556. display.showView(view1);
  557. manager.setState("test1/bar");
  558. listener1.addExpectedNavigatorViewChange(event3);
  559. listener2.addExpectedNavigatorViewChange(event3);
  560. // both listeners allow view change from non-null view
  561. EasyMock.expect(provider.getViewName("test2")).andReturn("test2")
  562. .times(2);
  563. EasyMock.expect(provider.getView("test2")).andReturn(view2);
  564. EasyMock.expect(manager.getState()).andReturn("view1");
  565. ViewChangeEvent event4 = new ViewChangeEvent(navigator, view1, view2,
  566. "test2", "");
  567. listener1.addExpectedIsViewChangeAllowed(event4, true);
  568. listener2.addExpectedIsViewChangeAllowed(event4, true);
  569. display.showView(view2);
  570. manager.setState("test2");
  571. listener1.addExpectedNavigatorViewChange(event4);
  572. listener2.addExpectedNavigatorViewChange(event4);
  573. control.replay();
  574. // test navigator
  575. navigator.addProvider(provider);
  576. navigator.addViewChangeListener(listener1);
  577. navigator.addViewChangeListener(listener2);
  578. navigator.navigateTo("test1");
  579. navigator.navigateTo("test1/test");
  580. navigator.navigateTo("test1/bar");
  581. navigator.navigateTo("test2");
  582. if (!listener1.isReady()) {
  583. fail("Missing listener calls for listener1");
  584. }
  585. if (!listener2.isReady()) {
  586. fail("Missing listener calls for listener2");
  587. }
  588. }
  589. @Test
  590. public void testAddViewInstance() throws Exception {
  591. View view = new TestView();
  592. TestNavigator navigator = new TestNavigator();
  593. navigator.addView("test", view);
  594. assertEquals("Registered view instance not returned by navigator", view,
  595. navigator.getView("test"));
  596. }
  597. @Test
  598. public void testAddViewInstanceSameName() throws Exception {
  599. View view1 = new TestView();
  600. View view2 = new TestView2();
  601. TestNavigator navigator = new TestNavigator();
  602. navigator.addView("test", view1);
  603. navigator.addView("test", view2);
  604. assertEquals(
  605. "Adding second view with same name should override previous view",
  606. view2, navigator.getView("test"));
  607. }
  608. @Test
  609. public void testAddViewClass() throws Exception {
  610. TestNavigator navigator = new TestNavigator();
  611. navigator.addView("test", TestView.class);
  612. View view = navigator.getView("test");
  613. assertNotNull("Received null view", view);
  614. assertEquals("Received incorrect type of view", TestView.class,
  615. view.getClass());
  616. }
  617. @Test
  618. public void testAddViewClassSameName() throws Exception {
  619. TestNavigator navigator = new TestNavigator();
  620. navigator.addView("test", TestView.class);
  621. navigator.addView("test", TestView2.class);
  622. assertEquals(
  623. "Adding second view class with same name should override previous view",
  624. TestView2.class, navigator.getView("test").getClass());
  625. }
  626. @Test
  627. public void testAddViewInstanceAndClassSameName() throws Exception {
  628. TestNavigator navigator = new TestNavigator();
  629. navigator.addView("test", TestView.class);
  630. TestView2 view2 = new TestView2();
  631. navigator.addView("test", view2);
  632. assertEquals(
  633. "Adding second view class with same name should override previous view",
  634. view2, navigator.getView("test"));
  635. navigator.addView("test", TestView.class);
  636. assertEquals(
  637. "Adding second view class with same name should override previous view",
  638. TestView.class, navigator.getView("test").getClass());
  639. }
  640. @Test
  641. public void testAddViewWithNullName() throws Exception {
  642. Navigator navigator = new TestNavigator();
  643. try {
  644. navigator.addView(null, new TestView());
  645. fail("addView() accepted null view name");
  646. } catch (IllegalArgumentException e) {
  647. }
  648. try {
  649. navigator.addView(null, TestView.class);
  650. fail("addView() accepted null view name");
  651. } catch (IllegalArgumentException e) {
  652. }
  653. }
  654. @Test(expected = IllegalArgumentException.class)
  655. public void testAddViewWithNullInstance() throws Exception {
  656. Navigator navigator = new TestNavigator();
  657. navigator.addView("test", (View) null);
  658. fail("addView() accepted null view instance");
  659. }
  660. @Test(expected = IllegalArgumentException.class)
  661. public void testAddViewWithNullClass() throws Exception {
  662. Navigator navigator = new TestNavigator();
  663. navigator.addView("test", (Class<View>) null);
  664. fail("addView() accepted null view class");
  665. }
  666. @Test
  667. public void testRemoveViewInstance() throws Exception {
  668. View view = new TestView();
  669. TestNavigator navigator = new TestNavigator();
  670. navigator.addView("test", view);
  671. navigator.removeView("test");
  672. assertNull("View not removed", navigator.getView("test"));
  673. }
  674. @Test
  675. public void testRemoveViewInstanceNothingElse() throws Exception {
  676. View view = new TestView();
  677. View view2 = new TestView2();
  678. TestNavigator navigator = new TestNavigator();
  679. navigator.addView("test", view);
  680. navigator.addView("test2", view2);
  681. navigator.removeView("test");
  682. assertEquals("Removed extra views", view2, navigator.getView("test2"));
  683. }
  684. @Test
  685. public void testRemoveViewClass() throws Exception {
  686. TestNavigator navigator = new TestNavigator();
  687. navigator.addView("test", TestView.class);
  688. navigator.removeView("test");
  689. assertNull("View not removed", navigator.getView("test"));
  690. }
  691. @Test
  692. public void testRemoveViewClassNothingElse() throws Exception {
  693. TestNavigator navigator = new TestNavigator();
  694. navigator.addView("test", TestView.class);
  695. navigator.addView("test2", TestView2.class);
  696. navigator.removeView("test");
  697. assertEquals("Removed extra views", TestView2.class,
  698. navigator.getView("test2").getClass());
  699. }
  700. @Test
  701. public void testGetViewNestedNames() throws Exception {
  702. TestNavigator navigator = new TestNavigator();
  703. navigator.addView("test/subview", TestView2.class);
  704. navigator.addView("test", TestView.class);
  705. assertEquals("Incorrect view name found for subview string",
  706. TestView2.class, navigator.getView("test/subview").getClass());
  707. assertEquals(
  708. "Incorrect view name found for subview string with empty parameters",
  709. TestView2.class, navigator.getView("test/subview/").getClass());
  710. assertEquals(
  711. "Incorrect view name found for subview string with parameters",
  712. TestView2.class,
  713. navigator.getView("test/subview/parameters").getClass());
  714. assertEquals("Incorrect view name found for top level view string",
  715. TestView.class, navigator.getView("test").getClass());
  716. assertEquals(
  717. "Incorrect view name found for top level view string with empty parameters",
  718. TestView.class, navigator.getView("test/").getClass());
  719. assertEquals(
  720. "Incorrect view name found for top level view string with parameters starting like subview name",
  721. TestView.class,
  722. navigator.getView("test/subviewnothere").getClass());
  723. }
  724. @Test
  725. public void testGetViewLongestPrefixOrder() throws Exception {
  726. TestNavigator navigator = new TestNavigator();
  727. navigator.addView("test/subview", TestView2.class);
  728. navigator.addView("test", TestView.class);
  729. assertEquals("Incorrect view name found", TestView.class,
  730. navigator.getView("test").getClass());
  731. // other order
  732. TestNavigator navigator2 = new TestNavigator();
  733. navigator2.addView("test", TestView.class);
  734. navigator2.addView("test/subview", TestView2.class);
  735. assertEquals("Incorrect view name found", TestView.class,
  736. navigator2.getView("test").getClass());
  737. }
  738. @Test
  739. public void testNavigateToUnknownView() {
  740. TestNavigator navigator = new TestNavigator();
  741. TestView errorView = new TestView();
  742. try {
  743. navigator.navigateTo("doesnotexist");
  744. fail("Should throw IllegalArgumentException");
  745. } catch (IllegalArgumentException iae) {
  746. }
  747. navigator.setErrorView(errorView);
  748. navigator.navigateTo("doesnotexist");
  749. TestView testView = new TestView();
  750. navigator.addView("doesnotexist", testView);
  751. navigator.navigateTo("doesnotexist");
  752. TestView errorView2 = new TestView();
  753. ViewProvider errorProvider = EasyMock.createMock(ViewProvider.class);
  754. EasyMock.expect(errorProvider.getView("doesnotexist2"))
  755. .andReturn(errorView2);
  756. EasyMock.expect(errorProvider.getViewName("doesnotexist2"))
  757. .andReturn("doesnotexist2");
  758. EasyMock.replay(errorProvider);
  759. navigator.setErrorProvider(errorProvider);
  760. navigator.navigateTo("doesnotexist2");
  761. }
  762. @Test
  763. public void testShowViewEnterOrder() {
  764. IMocksControl control = EasyMock.createStrictControl();
  765. View view = control.createMock(View.class);
  766. ViewDisplay display = control.createMock(ViewDisplay.class);
  767. display.showView(view);
  768. view.enter(EasyMock.anyObject(ViewChangeEvent.class));
  769. control.replay();
  770. NavigationStateManager manager = EasyMock
  771. .createNiceMock(NavigationStateManager.class);
  772. EasyMock.replay(manager);
  773. Navigator navigator = new Navigator(createMockUI(), manager, display);
  774. navigator.addView("view", view);
  775. navigator.navigateTo("view");
  776. }
  777. @Test(expected = IllegalArgumentException.class)
  778. public void testNullViewProvider() {
  779. IMocksControl control = EasyMock.createControl();
  780. NavigationStateManager manager = control
  781. .createMock(NavigationStateManager.class);
  782. ViewDisplay display = control.createMock(ViewDisplay.class);
  783. // create navigator to test
  784. Navigator navigator = createNavigator(manager, display);
  785. navigator.addProvider(null);
  786. fail("Should not be allowed to add a null view provider");
  787. }
  788. @Test
  789. public void testNavigateTo_navigateSameUriTwice_secondNavigationDoesNothing() {
  790. NavigationStateManager manager = new TestNavigationStateManager();
  791. final String viewName = "view";
  792. final View view = EasyMock.createMock(View.class);
  793. ViewProvider provider = new ViewProvider() {
  794. @Override
  795. public String getViewName(String viewAndParameters) {
  796. return viewName;
  797. }
  798. @Override
  799. public View getView(String viewName) {
  800. return view;
  801. }
  802. };
  803. final int[] count = { 0 };
  804. Navigator navigator = new Navigator(createMockUI(), manager,
  805. EasyMock.createMock(ViewDisplay.class)) {
  806. @Override
  807. protected void navigateTo(View view, String viewName,
  808. String parameters) {
  809. count[0] += 1;
  810. super.navigateTo(view, viewName, parameters);
  811. }
  812. };
  813. navigator.addProvider(provider);
  814. // First time navigation
  815. navigator.navigateTo(viewName);
  816. assertEquals(1, count[0]);
  817. // Second time navigation to the same view
  818. navigator.navigateTo(viewName);
  819. assertEquals(1, count[0]);
  820. }
  821. public static class ViewIsNotAComponent implements View {
  822. private HorizontalLayout layout = new HorizontalLayout(
  823. new Label("Hello"));
  824. @Override
  825. public Component getViewComponent() {
  826. return layout;
  827. }
  828. @Override
  829. public void enter(ViewChangeEvent event) {
  830. }
  831. }
  832. @Test
  833. public void viewWhichIsNotAComponent() {
  834. UI ui = new UI() {
  835. private Page page;
  836. {
  837. page = new Page(this, new PageState()) {
  838. private String fragment = "";
  839. @Override
  840. public String getUriFragment() {
  841. return fragment;
  842. };
  843. @Override
  844. public void setUriFragment(String newUriFragment,
  845. boolean fireEvents) {
  846. fragment = newUriFragment;
  847. };
  848. };
  849. }
  850. @Override
  851. protected void init(VaadinRequest request) {
  852. }
  853. @Override
  854. public Page getPage() {
  855. return page;
  856. }
  857. };
  858. Navigator navigator = new Navigator(ui, ui);
  859. ui.setNavigator(navigator);
  860. navigator.addView("foo", ViewIsNotAComponent.class);
  861. navigator.navigateTo("foo");
  862. assertEquals(HorizontalLayout.class, ui.getContent().getClass());
  863. assertEquals("Hello",
  864. ((Label) ((HorizontalLayout) ui.getContent()).getComponent(0))
  865. .getValue());
  866. }
  867. @Test
  868. public void parameterMap_noViewSeparator() {
  869. Navigator navigator = createNavigatorWithState("fooview");
  870. assertTrue(navigator.getStateParameterMap().isEmpty());
  871. assertTrue(navigator.getStateParameterMap("foo").isEmpty());
  872. }
  873. @Test
  874. public void parameterMap_noParameters() {
  875. Navigator navigator = createNavigatorWithState("fooview/");
  876. assertTrue(navigator.getStateParameterMap().isEmpty());
  877. }
  878. @Test
  879. public void parameterMap_oneParameterNoValue() {
  880. Navigator navigator = createNavigatorWithState("fooview/bar");
  881. assertMap(navigator.getStateParameterMap(), entry("bar", ""));
  882. }
  883. @Test
  884. public void parameterMap_oneParameterNoValueButEquals() {
  885. Navigator navigator = createNavigatorWithState("fooview/bar=");
  886. assertMap(navigator.getStateParameterMap(), entry("bar", ""));
  887. }
  888. @Test
  889. public void parameterMap_oneParameterWithValue() {
  890. Navigator navigator = createNavigatorWithState("fooview/bar=baz");
  891. assertMap(navigator.getStateParameterMap(), entry("bar", "baz"));
  892. }
  893. @Test
  894. public void parameterMap_twoParameters() {
  895. Navigator navigator = createNavigatorWithState("fooview/foo=bar&baz");
  896. assertMap(navigator.getStateParameterMap(), entry("foo", "bar"),
  897. entry("baz", ""));
  898. }
  899. @Test
  900. public void parameterMap_customSeparator() {
  901. Navigator navigator = createNavigatorWithState("fooview/foo=bar&baz");
  902. assertMap(navigator.getStateParameterMap("a"), entry("foo", "b"),
  903. entry("r&b", ""), entry("z", ""));
  904. }
  905. @SafeVarargs
  906. private final void assertMap(Map<String, String> map,
  907. Entry<String, String>... entries) {
  908. assertEquals(entries.length, map.size());
  909. for (Entry<String, String> entry : entries) {
  910. assertTrue(
  911. "Map should contain a key called '" + entry.getKey() + "'",
  912. map.containsKey(entry.getKey()));
  913. assertEquals(entry.getValue(), map.get(entry.getKey()));
  914. }
  915. }
  916. private Entry<String, String> entry(String key, String value) {
  917. return new Entry<String, String>() {
  918. @Override
  919. public String getKey() {
  920. return key;
  921. }
  922. @Override
  923. public String getValue() {
  924. return value;
  925. }
  926. @Override
  927. public String setValue(String value) {
  928. throw new UnsupportedOperationException();
  929. }
  930. };
  931. }
  932. private Navigator createNavigatorWithState(String state) {
  933. TestNavigationStateManager manager = new TestNavigationStateManager();
  934. Navigator navigator = new Navigator(createMockUI(), manager,
  935. EasyMock.createMock(ViewDisplay.class));
  936. manager.setState(state);
  937. return navigator;
  938. }
  939. @Test
  940. public void parameterMapFromViewChangeEvent() {
  941. Navigator navigator = createNavigatorWithState("foo");
  942. TestView view1 = new TestView();
  943. TestView view2 = new TestView();
  944. navigator.addView("view1", view1);
  945. navigator.addView("view2", view2);
  946. AtomicReference<Map<String, String>> mapRef = new AtomicReference<>();
  947. AtomicReference<Map<String, String>> mapRefB = new AtomicReference<>();
  948. navigator.addViewChangeListener(new ViewChangeListener() {
  949. @Override
  950. public boolean beforeViewChange(ViewChangeEvent event) {
  951. mapRef.set(event.getParameterMap());
  952. mapRefB.set(event.getParameterMap("b"));
  953. return true;
  954. }
  955. });
  956. navigator.navigateTo("view1");
  957. assertTrue(mapRef.get().isEmpty());
  958. assertTrue(mapRefB.get().isEmpty());
  959. navigator.navigateTo("view1/a&b=c&d");
  960. assertMap(mapRef.get(), entry("a", ""), entry("b", "c"),
  961. entry("d", ""));
  962. assertMap(mapRefB.get(), entry("a&", ""), entry("", "c&d"));
  963. }
  964. @Test
  965. public void view_beforeLeave_preventNavigation() {
  966. Navigator navigator = createNavigatorWithState("foo");
  967. View view1 = new View() {
  968. @Override
  969. public void enter(ViewChangeEvent event) {
  970. }
  971. @Override
  972. public void beforeLeave(ViewBeforeLeaveEvent event) {
  973. // Leaving this empty means the user can never leave
  974. }
  975. };
  976. View view2 = EasyMock.createMock(View.class);
  977. navigator.addView("view1", view1);
  978. navigator.addView("view2", view2);
  979. navigator.navigateTo("view1");
  980. navigator.navigateTo("view2");
  981. assertEquals("view1", navigator.getState());
  982. }
  983. @Test
  984. public void view_beforeLeave_allowNavigation() {
  985. Navigator navigator = createNavigatorWithState("foo");
  986. View view1 = new View() {
  987. @Override
  988. public void enter(ViewChangeEvent event) {
  989. }
  990. @Override
  991. public void beforeLeave(ViewBeforeLeaveEvent event) {
  992. event.navigate();
  993. }
  994. };
  995. View view2 = EasyMock.createMock(View.class);
  996. navigator.addView("view1", view1);
  997. navigator.addView("view2", view2);
  998. navigator.navigateTo("view1");
  999. navigator.navigateTo("view2");
  1000. assertEquals("view2", navigator.getState());
  1001. }
  1002. @Test
  1003. public void view_beforeLeave_delayNavigation() {
  1004. Navigator navigator = createNavigatorWithState("foo");
  1005. AtomicReference<ViewBeforeLeaveEvent> eventRef = new AtomicReference<ViewBeforeLeaveEvent>();
  1006. View view1 = new View() {
  1007. @Override
  1008. public void enter(ViewChangeEvent event) {
  1009. }
  1010. @Override
  1011. public void beforeLeave(ViewBeforeLeaveEvent event) {
  1012. eventRef.set(event);
  1013. }
  1014. };
  1015. View view2 = EasyMock.createMock(View.class);
  1016. navigator.addView("view1", view1);
  1017. navigator.addView("view2", view2);
  1018. navigator.navigateTo("view1");
  1019. navigator.navigateTo("view2");
  1020. assertEquals("view1", navigator.getState());
  1021. eventRef.get().navigate();
  1022. assertEquals("view2", navigator.getState());
  1023. }
  1024. @Test
  1025. public void navigator_invokeBeforeLeaveManually() {
  1026. Navigator navigator = createNavigatorWithState("foo");
  1027. AtomicReference<ViewBeforeLeaveEvent> eventRef = new AtomicReference<ViewBeforeLeaveEvent>();
  1028. View view1 = new View() {
  1029. @Override
  1030. public void enter(ViewChangeEvent event) {
  1031. }
  1032. @Override
  1033. public void beforeLeave(ViewBeforeLeaveEvent event) {
  1034. eventRef.set(event);
  1035. }
  1036. };
  1037. TestView view2 = new TestView();
  1038. navigator.addView("view1", view1);
  1039. navigator.addView("view2", view2);
  1040. navigator.navigateTo("view1");
  1041. AtomicInteger leaveCount = new AtomicInteger(0);
  1042. navigator.runAfterLeaveConfirmation(() -> leaveCount.incrementAndGet());
  1043. assertEquals(0, leaveCount.get());
  1044. eventRef.get().navigate();
  1045. assertEquals(1, leaveCount.get());
  1046. assertEquals("view1", navigator.getState());
  1047. }
  1048. }