You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BinderValidationStatusTest.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  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.data;
  17. import java.util.List;
  18. import java.util.concurrent.atomic.AtomicReference;
  19. import org.junit.Assert;
  20. import org.junit.Before;
  21. import org.junit.Test;
  22. import com.vaadin.data.Binder.Binding;
  23. import com.vaadin.data.Binder.BindingBuilder;
  24. import com.vaadin.data.ValidationStatus.Status;
  25. import com.vaadin.tests.data.bean.Person;
  26. import com.vaadin.ui.Label;
  27. public class BinderValidationStatusTest
  28. extends BinderTestBase<Binder<Person>, Person> {
  29. protected final static ValidationStatusHandler NOOP = event -> {
  30. };
  31. @Before
  32. public void setUp() {
  33. binder = new Binder<>();
  34. item = new Person();
  35. item.setFirstName("Johannes");
  36. item.setAge(32);
  37. }
  38. //
  39. // Binding-level status handler
  40. //
  41. @Test
  42. public void bindingWithStatusHandler_handlerGetsEvents() {
  43. AtomicReference<ValidationStatus<?>> statusCapture = new AtomicReference<>();
  44. BindingBuilder<Person, String> binding = binder.forField(nameField)
  45. .withValidator(notEmpty).withValidationStatusHandler(evt -> {
  46. Assert.assertNull(statusCapture.get());
  47. statusCapture.set(evt);
  48. });
  49. binding.bind(Person::getFirstName, Person::setFirstName);
  50. nameField.setValue("");
  51. // First validation fails => should be event with ERROR status and
  52. // message
  53. binder.validate();
  54. Assert.assertNotNull(statusCapture.get());
  55. ValidationStatus<?> evt = statusCapture.get();
  56. Assert.assertEquals(Status.ERROR, evt.getStatus());
  57. Assert.assertEquals(EMPTY_ERROR_MESSAGE, evt.getMessage().get());
  58. Assert.assertEquals(nameField, evt.getField());
  59. statusCapture.set(null);
  60. nameField.setValue("foo");
  61. statusCapture.set(null);
  62. // Second validation succeeds => should be event with OK status and
  63. // no message
  64. binder.validate();
  65. evt = statusCapture.get();
  66. Assert.assertNotNull(evt);
  67. Assert.assertEquals(Status.OK, evt.getStatus());
  68. Assert.assertFalse(evt.getMessage().isPresent());
  69. Assert.assertEquals(nameField, evt.getField());
  70. }
  71. @Test
  72. public void bindingWithStatusHandler_defaultStatusHandlerIsReplaced() {
  73. Binding<Person, String> binding = binder.forField(nameField)
  74. .withValidator(notEmpty).withValidationStatusHandler(evt -> {
  75. }).bind(Person::getFirstName, Person::setFirstName);
  76. Assert.assertNull(nameField.getComponentError());
  77. nameField.setValue("");
  78. // First validation fails => should be event with ERROR status and
  79. // message
  80. binding.validate();
  81. // default behavior should update component error for the nameField
  82. Assert.assertNull(nameField.getComponentError());
  83. }
  84. @Test
  85. public void bindingWithStatusLabel_labelIsUpdatedAccordingStatus() {
  86. Label label = new Label();
  87. Binding<Person, String> binding = binder.forField(nameField)
  88. .withValidator(notEmpty).withStatusLabel(label)
  89. .bind(Person::getFirstName, Person::setFirstName);
  90. nameField.setValue("");
  91. // First validation fails => should be event with ERROR status and
  92. // message
  93. binding.validate();
  94. Assert.assertTrue(label.isVisible());
  95. Assert.assertEquals(EMPTY_ERROR_MESSAGE, label.getValue());
  96. nameField.setValue("foo");
  97. // Second validation succeeds => should be event with OK status and
  98. // no message
  99. binding.validate();
  100. Assert.assertFalse(label.isVisible());
  101. Assert.assertEquals("", label.getValue());
  102. }
  103. @Test
  104. public void bindingWithStatusLabel_defaultStatusHandlerIsReplaced() {
  105. Label label = new Label();
  106. Binding<Person, String> binding = binder.forField(nameField)
  107. .withValidator(notEmpty).withStatusLabel(label)
  108. .bind(Person::getFirstName, Person::setFirstName);
  109. Assert.assertNull(nameField.getComponentError());
  110. nameField.setValue("");
  111. // First validation fails => should be event with ERROR status and
  112. // message
  113. binding.validate();
  114. // default behavior should update component error for the nameField
  115. Assert.assertNull(nameField.getComponentError());
  116. }
  117. @Test(expected = IllegalStateException.class)
  118. public void bindingWithStatusHandler_addAfterBound() {
  119. BindingBuilder<Person, String> binding = binder.forField(nameField)
  120. .withValidator(notEmpty);
  121. binding.bind(Person::getFirstName, Person::setFirstName);
  122. binding.withValidationStatusHandler(evt -> Assert.fail());
  123. }
  124. @Test(expected = IllegalStateException.class)
  125. public void bindingWithStatusLabel_addAfterBound() {
  126. Label label = new Label();
  127. BindingBuilder<Person, String> binding = binder.forField(nameField)
  128. .withValidator(notEmpty);
  129. binding.bind(Person::getFirstName, Person::setFirstName);
  130. binding.withStatusLabel(label);
  131. }
  132. @Test(expected = IllegalStateException.class)
  133. public void bindingWithStatusLabel_setAfterHandler() {
  134. Label label = new Label();
  135. BindingBuilder<Person, String> binding = binder.forField(nameField);
  136. binding.withValidationStatusHandler(NOOP);
  137. binding.withStatusLabel(label);
  138. }
  139. @Test(expected = IllegalStateException.class)
  140. public void bindingWithStatusHandler_setAfterLabel() {
  141. Label label = new Label();
  142. BindingBuilder<Person, String> binding = binder.forField(nameField);
  143. binding.withStatusLabel(label);
  144. binding.withValidationStatusHandler(NOOP);
  145. }
  146. @Test(expected = IllegalStateException.class)
  147. public void bindingWithStatusHandler_setAfterOtherHandler() {
  148. BindingBuilder<Person, String> binding = binder.forField(nameField);
  149. binding.withValidationStatusHandler(NOOP);
  150. binding.withValidationStatusHandler(NOOP);
  151. }
  152. //
  153. // Binder-level status handler
  154. //
  155. @Test
  156. public void binderWithStatusHandler_fieldValidationNoBeanValidation_handlerGetsStatusUpdates() {
  157. AtomicReference<BinderValidationStatus<?>> statusCapture = new AtomicReference<>();
  158. binder.forField(nameField).withValidator(notEmpty)
  159. .withValidationStatusHandler(evt -> {
  160. Assert.fail(
  161. "Using a custom status change handler so no change should end up here");
  162. }).bind(Person::getFirstName, Person::setFirstName);
  163. binder.forField(ageField).withConverter(stringToInteger)
  164. .withValidator(notNegative).withValidationStatusHandler(evt -> {
  165. Assert.fail(
  166. "Using a custom status change handler so no change should end up here");
  167. }).bind(Person::getAge, Person::setAge);
  168. binder.setValidationStatusHandler(r -> {
  169. statusCapture.set(r);
  170. });
  171. binder.setBean(item);
  172. Assert.assertNull(nameField.getComponentError());
  173. nameField.setValue("");
  174. ageField.setValue("5");
  175. // First binding validation fails => should be result with ERROR status
  176. // and message
  177. BinderValidationStatus<Person> status2 = binder.validate();
  178. BinderValidationStatus<?> status = statusCapture.get();
  179. Assert.assertSame(status2, status);
  180. Assert.assertNull(nameField.getComponentError());
  181. List<ValidationStatus<?>> bindingStatuses = status
  182. .getFieldValidationStatuses();
  183. Assert.assertNotNull(bindingStatuses);
  184. Assert.assertEquals(1, status.getFieldValidationErrors().size());
  185. Assert.assertEquals(2, bindingStatuses.size());
  186. ValidationStatus<?> r = bindingStatuses.get(0);
  187. Assert.assertTrue(r.isError());
  188. Assert.assertEquals(EMPTY_ERROR_MESSAGE, r.getMessage().get());
  189. Assert.assertEquals(nameField, r.getField());
  190. r = bindingStatuses.get(1);
  191. Assert.assertFalse(r.isError());
  192. Assert.assertFalse(r.getMessage().isPresent());
  193. Assert.assertEquals(ageField, r.getField());
  194. Assert.assertEquals(0, status.getBeanValidationResults().size());
  195. Assert.assertEquals(0, status.getBeanValidationErrors().size());
  196. nameField.setValue("foo");
  197. ageField.setValue("");
  198. statusCapture.set(null);
  199. // Second validation succeeds => should be result with OK status and
  200. // no message, and error result for age
  201. binder.validate();
  202. status = statusCapture.get();
  203. bindingStatuses = status.getFieldValidationStatuses();
  204. Assert.assertEquals(1, status.getFieldValidationErrors().size());
  205. Assert.assertEquals(2, bindingStatuses.size());
  206. r = bindingStatuses.get(0);
  207. Assert.assertFalse(r.isError());
  208. Assert.assertFalse(r.getMessage().isPresent());
  209. Assert.assertEquals(nameField, r.getField());
  210. r = bindingStatuses.get(1);
  211. Assert.assertTrue(r.isError());
  212. Assert.assertEquals("Value must be a number", r.getMessage().get());
  213. Assert.assertEquals(ageField, r.getField());
  214. Assert.assertEquals(0, status.getBeanValidationResults().size());
  215. Assert.assertEquals(0, status.getBeanValidationErrors().size());
  216. statusCapture.set(null);
  217. // binding validations pass, binder validation fails
  218. ageField.setValue("0");
  219. binder.validate();
  220. status = statusCapture.get();
  221. bindingStatuses = status.getFieldValidationStatuses();
  222. Assert.assertEquals(0, status.getFieldValidationErrors().size());
  223. Assert.assertEquals(2, bindingStatuses.size());
  224. Assert.assertEquals(0, status.getBeanValidationResults().size());
  225. Assert.assertEquals(0, status.getBeanValidationErrors().size());
  226. }
  227. @Test
  228. public void binderWithStatusHandler_fieldAndBeanLevelValidation_handlerGetsStatusUpdates() {
  229. AtomicReference<BinderValidationStatus<?>> statusCapture = new AtomicReference<>();
  230. binder.forField(nameField).withValidator(notEmpty)
  231. .withValidationStatusHandler(evt -> {
  232. Assert.fail(
  233. "Using a custom status change handler so no change should end up here");
  234. }).bind(Person::getFirstName, Person::setFirstName);
  235. binder.forField(ageField).withConverter(stringToInteger)
  236. .withValidator(notNegative).withValidationStatusHandler(evt -> {
  237. Assert.fail(
  238. "Using a custom status change handler so no change should end up here");
  239. }).bind(Person::getAge, Person::setAge);
  240. binder.withValidator(
  241. bean -> !bean.getFirstName().isEmpty() && bean.getAge() > 0,
  242. "Need first name and age");
  243. binder.setValidationStatusHandler(r -> {
  244. statusCapture.set(r);
  245. });
  246. binder.setBean(item);
  247. Assert.assertNull(nameField.getComponentError());
  248. nameField.setValue("");
  249. ageField.setValue("5");
  250. // First binding validation fails => should be result with ERROR status
  251. // and message
  252. BinderValidationStatus<Person> status2 = binder.validate();
  253. BinderValidationStatus<?> status = statusCapture.get();
  254. Assert.assertSame(status2, status);
  255. Assert.assertNull(nameField.getComponentError());
  256. List<ValidationStatus<?>> bindingStatuses = status
  257. .getFieldValidationStatuses();
  258. Assert.assertNotNull(bindingStatuses);
  259. Assert.assertEquals(1, status.getFieldValidationErrors().size());
  260. Assert.assertEquals(2, bindingStatuses.size());
  261. ValidationStatus<?> r = bindingStatuses.get(0);
  262. Assert.assertTrue(r.isError());
  263. Assert.assertEquals(EMPTY_ERROR_MESSAGE, r.getMessage().get());
  264. Assert.assertEquals(nameField, r.getField());
  265. r = bindingStatuses.get(1);
  266. Assert.assertFalse(r.isError());
  267. Assert.assertFalse(r.getMessage().isPresent());
  268. Assert.assertEquals(ageField, r.getField());
  269. Assert.assertEquals(0, status.getBeanValidationResults().size());
  270. Assert.assertEquals(0, status.getBeanValidationErrors().size());
  271. nameField.setValue("foo");
  272. ageField.setValue("");
  273. statusCapture.set(null);
  274. // Second validation succeeds => should be result with OK status and
  275. // no message, and error result for age
  276. binder.validate();
  277. status = statusCapture.get();
  278. bindingStatuses = status.getFieldValidationStatuses();
  279. Assert.assertEquals(1, status.getFieldValidationErrors().size());
  280. Assert.assertEquals(2, bindingStatuses.size());
  281. r = bindingStatuses.get(0);
  282. Assert.assertFalse(r.isError());
  283. Assert.assertFalse(r.getMessage().isPresent());
  284. Assert.assertEquals(nameField, r.getField());
  285. r = bindingStatuses.get(1);
  286. Assert.assertTrue(r.isError());
  287. Assert.assertEquals("Value must be a number", r.getMessage().get());
  288. Assert.assertEquals(ageField, r.getField());
  289. Assert.assertEquals(0, status.getBeanValidationResults().size());
  290. Assert.assertEquals(0, status.getBeanValidationErrors().size());
  291. statusCapture.set(null);
  292. // binding validations pass, binder validation fails
  293. ageField.setValue("0");
  294. binder.validate();
  295. status = statusCapture.get();
  296. bindingStatuses = status.getFieldValidationStatuses();
  297. Assert.assertEquals(0, status.getFieldValidationErrors().size());
  298. Assert.assertEquals(2, bindingStatuses.size());
  299. Assert.assertEquals(1, status.getBeanValidationResults().size());
  300. Assert.assertEquals(1, status.getBeanValidationErrors().size());
  301. Assert.assertEquals("Need first name and age",
  302. status.getBeanValidationErrors().get(0).getErrorMessage());
  303. }
  304. @Test
  305. public void binderWithStatusHandler_defaultStatusHandlerIsReplaced() {
  306. Binding<Person, String> binding = binder.forField(nameField)
  307. .withValidator(notEmpty).withValidationStatusHandler(evt -> {
  308. }).bind(Person::getFirstName, Person::setFirstName);
  309. Assert.assertNull(nameField.getComponentError());
  310. nameField.setValue("");
  311. // First validation fails => should be event with ERROR status and
  312. // message
  313. binding.validate();
  314. // no component error since default handler is replaced
  315. Assert.assertNull(nameField.getComponentError());
  316. }
  317. @Test
  318. public void binderWithStatusLabel_defaultStatusHandlerIsReplaced() {
  319. Label label = new Label();
  320. Binding<Person, String> binding = binder.forField(nameField)
  321. .withValidator(notEmpty).withStatusLabel(label)
  322. .bind(Person::getFirstName, Person::setFirstName);
  323. Assert.assertNull(nameField.getComponentError());
  324. nameField.setValue("");
  325. // First validation fails => should be event with ERROR status and
  326. // message
  327. binding.validate();
  328. // default behavior should update component error for the nameField
  329. Assert.assertNull(nameField.getComponentError());
  330. }
  331. @Test(expected = IllegalStateException.class)
  332. public void binderWithStatusHandler_addAfterBound() {
  333. BindingBuilder<Person, String> binding = binder.forField(nameField)
  334. .withValidator(notEmpty);
  335. binding.bind(Person::getFirstName, Person::setFirstName);
  336. binding.withValidationStatusHandler(evt -> Assert.fail());
  337. }
  338. @Test(expected = IllegalStateException.class)
  339. public void binderWithStatusLabel_addAfterBound() {
  340. Label label = new Label();
  341. BindingBuilder<Person, String> binding = binder.forField(nameField)
  342. .withValidator(notEmpty);
  343. binding.bind(Person::getFirstName, Person::setFirstName);
  344. binding.withStatusLabel(label);
  345. }
  346. @Test(expected = IllegalStateException.class)
  347. public void binderWithStatusLabel_setAfterHandler() {
  348. Label label = new Label();
  349. BindingBuilder<Person, String> binding = binder.forField(nameField);
  350. binding.bind(Person::getFirstName, Person::setFirstName);
  351. binder.setValidationStatusHandler(event -> {
  352. });
  353. binder.setStatusLabel(label);
  354. }
  355. @Test(expected = IllegalStateException.class)
  356. public void binderWithStatusHandler_setAfterLabel() {
  357. Label label = new Label();
  358. BindingBuilder<Person, String> binding = binder.forField(nameField);
  359. binding.bind(Person::getFirstName, Person::setFirstName);
  360. binder.setStatusLabel(label);
  361. binder.setValidationStatusHandler(event -> {
  362. });
  363. }
  364. @Test(expected = NullPointerException.class)
  365. public void binderWithNullStatusHandler_throws() {
  366. binder.setValidationStatusHandler(null);
  367. }
  368. @Test
  369. public void binderWithStatusHandler_replaceHandler() {
  370. AtomicReference<BinderValidationStatus<?>> capture = new AtomicReference<>();
  371. BindingBuilder<Person, String> binding = binder.forField(nameField);
  372. binding.bind(Person::getFirstName, Person::setFirstName);
  373. binder.setValidationStatusHandler(results -> {
  374. Assert.fail();
  375. });
  376. binder.setValidationStatusHandler(results -> {
  377. capture.set(results);
  378. });
  379. nameField.setValue("foo");
  380. binder.validate();
  381. List<ValidationStatus<?>> results = capture.get()
  382. .getFieldValidationStatuses();
  383. Assert.assertNotNull(results);
  384. Assert.assertEquals(1, results.size());
  385. Assert.assertFalse(results.get(0).isError());
  386. }
  387. }