View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
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,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.service.impl;
17  
18  import org.junit.Assert;
19  import org.junit.Before;
20  import org.junit.Test;
21  import org.kuali.rice.krad.test.KRADTestCase;
22  import org.kuali.rice.core.api.util.RiceKeyConstants;
23  import org.kuali.rice.krad.datadictionary.DataDictionary;
24  import org.kuali.rice.krad.datadictionary.DataObjectEntry;
25  import org.kuali.rice.krad.datadictionary.validation.Address;
26  import org.kuali.rice.krad.datadictionary.validation.Company;
27  import org.kuali.rice.krad.datadictionary.validation.Employee;
28  import org.kuali.rice.krad.datadictionary.validation.ErrorLevel;
29  import org.kuali.rice.krad.datadictionary.validation.Person;
30  import org.kuali.rice.krad.datadictionary.validation.constraint.provider.CollectionDefinitionConstraintProvider;
31  import org.kuali.rice.krad.datadictionary.validation.processor.MustOccurConstraintProcessor;
32  import org.kuali.rice.krad.datadictionary.validation.result.ConstraintValidationResult;
33  import org.kuali.rice.krad.datadictionary.validation.result.DictionaryValidationResult;
34  import org.kuali.rice.krad.service.DataDictionaryService;
35  import org.springframework.context.support.ClassPathXmlApplicationContext;
36  
37  import java.io.IOException;
38  import java.util.ArrayList;
39  import java.util.Date;
40  import java.util.Iterator;
41  import java.util.List;
42  
43  /**
44   * DictionaryValidationServiceImplTest tests {@link DictionaryValidationServiceImpl} using the data dictionary
45   * configurations in
46   * org/kuali/rice/krad/test/datadictionary/validation
47   *
48   * @author Kuali Rice Team (rice.collab@kuali.org)
49   */
50  public class DictionaryValidationServiceImplTest extends KRADTestCase {
51  
52      ClassPathXmlApplicationContext context;
53      private DictionaryValidationServiceImpl service;
54      DataDictionary dataDictionary = new DataDictionary();
55  
56      protected DataObjectEntry addressEntry;
57  
58      private Address validLondonAddress = new Address("8129 Maiden Lane", "", "London", "", "SE1 0P3", "UK", null);
59      private Address validUSAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031",
60              "USA", null);
61      private Address invalidUSAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "",
62              "92342-123456", "USA", null);
63      private Address noZipNoCityUSAddress = new Address("893 Presidential Ave", "Suite 800", null, "DC", null, "USA",
64              null);
65      private Address validNonDCUSAddress = new Address("89 11th Street", "Suite 800", "Seattle", "WA", "", "USA", null);
66      private Address invalidDCUSAddress = new Address("89 Presidential Ave", "Suite 800", "Washington", "DC", "12031",
67              "USA", null);
68      private Address invalidHKAddress = new Address("182 Lin Pai Road", "", "Hong Kong", "N.T.", "", "CN", null);
69  
70      @Before
71      public void setUp() throws Exception {
72          super.setUp();
73  
74          context = new ClassPathXmlApplicationContext("classpath:DictionaryValidationServiceSpringBeans.xml");
75  
76          service = (DictionaryValidationServiceImpl) context.getBean("dictionaryValidationService");
77  
78          dataDictionary.addConfigFileLocation("KR-NS",
79                  "classpath:org/kuali/rice/krad/datadictionary/DataDictionaryBaseTypes.xml");
80          dataDictionary.addConfigFileLocation("KR-NS",
81                  "classpath:org/kuali/rice/kns/bo/datadictionary/DataDictionaryBaseTypes.xml");
82          dataDictionary.addConfigFileLocation("KR-NS",
83                  "classpath:org/kuali/rice/krad/test/datadictionary/validation/Company.xml");
84          dataDictionary.addConfigFileLocation("KR-NS",
85                  "classpath:org/kuali/rice/krad/test/datadictionary/validation/Address.xml");
86          dataDictionary.addConfigFileLocation("KR-NS",
87                  "classpath:org/kuali/rice/krad/test/datadictionary/validation/Employee.xml");
88          dataDictionary.addConfigFileLocation("KR-NS","classpath:org/kuali/rice/krad/test/datadictionary/validation/Person.xml");
89  
90          dataDictionary.parseDataDictionaryConfigurationFiles(false);
91  
92          addressEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Address");
93      }
94  
95      @Test
96      /**
97       * tests that a valid non US address will not generate warnings or errors
98       *
99       * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
100      * @see org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint
101      */
102     public void testValidNonUSAddress() {
103         DictionaryValidationResult dictionaryValidationResult = service.validate(validLondonAddress,
104                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
105 
106         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
107         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
108     }
109 
110     @Test
111     /**
112      * tests that a valid US address will not generate warnings or errors
113      *
114      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
115      * @see org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint
116      */
117     public void testValidUSAddress() {
118         DictionaryValidationResult dictionaryValidationResult = service.validate(validUSAddress,
119                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
120 
121         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
122         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
123     }
124 
125     @Test
126     /**
127      * tests that an invalid US address will generate the expected errors
128      *
129      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
130      * @see org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint
131      */
132     public void testInvalidUSAddress() {
133         DictionaryValidationResult dictionaryValidationResult = service.validate(invalidUSAddress,
134                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
135 
136         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
137         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
138 
139         Assert.assertTrue(hasError(dictionaryValidationResult, "country", RiceKeyConstants.ERROR_REQUIRES_FIELD));
140         Assert.assertTrue(hasError(dictionaryValidationResult, "postalCode", RiceKeyConstants.ERROR_OUT_OF_RANGE));
141     }
142 
143     @Test
144     /**
145      * tests that a valid US address will not generate warnings or errors
146      *
147      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
148      * @see org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint
149      */
150     public void testValidNonDCAddress() {
151         DictionaryValidationResult dictionaryValidationResult = service.validate(validNonDCUSAddress,
152                 "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
153 
154         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
155         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
156     }
157 
158     @Test
159     /**
160      * tests that an invalid DC address will generate the expected errors
161      *
162      * <p>the attribute street1 has a ValidCharacters constraint that is activated when the state attribute has the value 'DC'</p>
163      *
164      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
165      * @see org.kuali.rice.krad.datadictionary.validation.constraint.WhenConstraint
166      * @see DictionaryValidationResult
167      */
168     public void testInvalidDCAddress() {
169         DictionaryValidationResult dictionaryValidationResult = service.validate(invalidDCUSAddress,
170                 "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
171 
172         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
173         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
174 
175         Assert.assertTrue(hasError(dictionaryValidationResult, "street1", RiceKeyConstants.ERROR_INVALID_FORMAT));
176     }
177 
178     @Test
179     /**
180      * test that the error produced for an invalid US address has the expected attributes
181      *
182      * <p>Address has a must occur constraint where either the postal code must be entered or _both_ the city and state</p>
183      *
184      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
185      * @see ConstraintValidationResult
186      * @see org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint
187      */
188     public void testNoStateNoZipUSAddress() {
189         DictionaryValidationResult dictionaryValidationResult = service.validate(noZipNoCityUSAddress,
190                 "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
191 
192         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
193         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
194 
195         if (dictionaryValidationResult.getNumberOfErrors() > 0) {
196             for (Iterator<ConstraintValidationResult> iterator = dictionaryValidationResult.iterator();
197                  iterator.hasNext(); ) {
198                 ConstraintValidationResult constraintValidationResult = iterator.next();
199                 if (constraintValidationResult.getStatus().getLevel() >= ErrorLevel.WARN.getLevel()) {
200                     // The top level error should be an occurs error
201                     Assert.assertEquals(ErrorLevel.ERROR, constraintValidationResult.getStatus());
202                     Assert.assertEquals("error.occurs", constraintValidationResult.getErrorKey());
203                     // It should have two children
204                     List<ConstraintValidationResult> children = constraintValidationResult.getChildren();
205                     Assert.assertNotNull(children);
206                     Assert.assertEquals(2, children.size());
207                     // The first child should have it's own child
208                     ConstraintValidationResult child1 = children.get(0);
209                     ConstraintValidationResult child2 = children.get(1);
210 
211                     Assert.assertEquals("error.requiresField", child1.getErrorKey());
212                     Assert.assertArrayEquals(new String[]{"postalCode"}, child1.getErrorParameters());
213 
214                     List<ConstraintValidationResult> grandchildren = child2.getChildren();
215                     Assert.assertNotNull(grandchildren);
216                     Assert.assertEquals(2, grandchildren.size());
217                     ConstraintValidationResult grandchild1 = grandchildren.get(0);
218                     Assert.assertEquals(ErrorLevel.ERROR, grandchild1.getStatus());
219                     Assert.assertEquals("error.requiresField", grandchild1.getErrorKey());
220                     Assert.assertArrayEquals(new String[]{"city"}, grandchild1.getErrorParameters());
221                     ConstraintValidationResult grandchild2 = grandchildren.get(1);
222                     Assert.assertEquals(ErrorLevel.OK, grandchild2.getStatus());
223                     Assert.assertEquals(new MustOccurConstraintProcessor().getName(), grandchild2.getConstraintName());
224                 }
225             }
226         }
227     }
228 
229     @Test
230     /**
231      * tests that an error is generated when an address where the country attribute is 'CN' has not value for street2
232      *
233      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
234      * @see org.kuali.rice.krad.datadictionary.validation.constraint.WhenConstraint
235      * @see org.kuali.rice.krad.datadictionary.validation.constraint.SimpleConstraint
236      */
237     public void testSimpleCaseConstraints() throws IOException {
238         DictionaryValidationResult dictionaryValidationResult = service.validate(invalidHKAddress,
239                 "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
240 
241         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
242         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
243 
244         Assert.assertTrue(hasError(dictionaryValidationResult, "street2", RiceKeyConstants.ERROR_REQUIRED));
245     }
246 
247     @Test
248     /**
249      * tests that nested attributes are validated as expected
250      *
251      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
252      * @see DictionaryValidationResult
253      */
254     public void testRequiredNestedAttribute() throws IOException {
255         DataDictionaryService dataDictionaryService = new DataDictionaryServiceImpl(dataDictionary);
256         service.setDataDictionaryService(dataDictionaryService);
257 
258         //Get object entries from dictionary
259         DataObjectEntry addressEntry = dataDictionary.getDataObjectEntry(
260                 "org.kuali.rice.krad.datadictionary.validation.Address");
261         DataObjectEntry companyEntry = dataDictionary.getDataObjectEntry(
262                 "org.kuali.rice.krad.datadictionary.validation.Company");
263 
264         //Validate object entries
265         addressEntry.completeValidation();
266         companyEntry.completeValidation();
267 
268         Company acmeCompany = new Company();
269 
270         //Validate empty Company object
271         DictionaryValidationResult dictionaryValidationResult;
272         dictionaryValidationResult = service.validate(acmeCompany,
273                 "org.kuali.rice.krad.datadictionary.validation.Company", companyEntry, true);
274 
275         //Main address is required this should result in error
276         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
277         Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress", RiceKeyConstants.ERROR_REQUIRED));
278 
279         //Adding an invalid mainAddress for company
280         Address acmeMainAddress = new Address();
281         acmeCompany.setMainAddress(acmeMainAddress);
282 
283         dictionaryValidationResult = service.validate(acmeCompany,
284                 "org.kuali.rice.krad.datadictionary.validation.Company", companyEntry, true);
285 
286         //This should result in missing country error
287         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
288         Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress.country", RiceKeyConstants.ERROR_REQUIRED));
289         Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress", RiceKeyConstants.ERROR_OCCURS));
290 
291         //Set items to valid address
292         acmeMainAddress.setCountry("US");
293         acmeMainAddress.setPostalCode("11111");
294 
295         dictionaryValidationResult = service.validate(acmeCompany,
296                 "org.kuali.rice.krad.datadictionary.validation.Company", companyEntry, true);
297 
298         //This should result in no error
299         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
300 
301         //Test Nested Attribute Within Nested Attribute, and nested property override
302         Employee companyContact = new Employee();
303         acmeCompany.setMainContact(companyContact);
304         Person mainContactPerson = new Person();
305         companyContact.setEmployeeDetails(mainContactPerson);
306         companyContact.setEmployeeId("companyContact");
307 
308         dictionaryValidationResult = service.validate(acmeCompany,
309                 "org.kuali.rice.krad.datadictionary.validation.Company", companyEntry, true);
310 
311         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
312         Assert.assertTrue(hasError(dictionaryValidationResult, "mainContact.employeeDetails.gender",
313                 RiceKeyConstants.ERROR_REQUIRED));
314     }
315 
316     @Test
317     /**
318      * tests the collection definition as defined in org/kuali/rice/krad/test/datadictionary/validation/Company.xml
319      *
320      * @see org.kuali.rice.krad.datadictionary.CollectionDefinition
321      * @see DictionaryValidationServiceImpl#validate(Object, String, String, boolean)
322      */
323     public void testCollectionConstraints() throws IOException {
324         DataDictionaryService dataDictionaryService = new DataDictionaryServiceImpl(dataDictionary);
325         service.setDataDictionaryService(dataDictionaryService);
326 
327         DataObjectEntry companyEntry = dataDictionary.getDataObjectEntry(
328                 "org.kuali.rice.krad.datadictionary.validation.Company");
329 
330         //Add collection constraint provider so constraints on collections get processed
331         service.getConstraintProviders().add(new CollectionDefinitionConstraintProvider());
332 
333         Company acmeCompany = new Company();
334         Address acmeMainAddress = new Address();
335         acmeMainAddress.setCountry("US");
336         acmeMainAddress.setPostalCode("11111");
337         acmeCompany.setMainAddress(acmeMainAddress);
338 
339         DictionaryValidationResult dictionaryValidationResult = service.validate(acmeCompany,
340                 "org.kuali.rice.krad.datadictionary.validation.Company", companyEntry, true);
341 
342         //Company requires at least two employees
343         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
344         Assert.assertTrue(hasError(dictionaryValidationResult, "employees", RiceKeyConstants.ERROR_QUANTITY_RANGE));
345         Assert.assertTrue(hasError(dictionaryValidationResult, "slogans", RiceKeyConstants.ERROR_MIN_OCCURS));
346 
347         //Add required employes and revalidate
348         Employee employee1 = new Employee();
349         Person person = new Person();
350         person.setBirthDate(new Date());
351         person.setGender("M");
352         employee1.setEmployeeDetails(person);
353         employee1.setEmployeeId("123456789");
354 
355         List<Employee> employees = new ArrayList<Employee>();
356         employees.add(employee1);
357         acmeCompany.setEmployees(employees);
358 
359         List<String> slogans = new ArrayList<String>();
360         slogans.add("Slogan One");
361         acmeCompany.setSlogans(slogans);
362 
363         dictionaryValidationResult = service.validate(acmeCompany,
364                 "org.kuali.rice.krad.datadictionary.validation.Company", companyEntry, true);
365         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
366         Assert.assertTrue(hasError(dictionaryValidationResult, "employees", RiceKeyConstants.ERROR_QUANTITY_RANGE));
367         Assert.assertTrue(hasError(dictionaryValidationResult, "slogans", RiceKeyConstants.ERROR_MIN_OCCURS));
368 
369         //Add two invalid employees, this should result in size constraint, and invalid employee errors
370         employees.add(new Employee());
371         employees.add(new Employee());
372         slogans.add("Slogan Two");
373 
374         dictionaryValidationResult = service.validate(acmeCompany,
375                 "org.kuali.rice.krad.datadictionary.validation.Company", companyEntry, true);
376         Assert.assertEquals(5, dictionaryValidationResult.getNumberOfErrors());
377 
378         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[1].employeeId",
379                 RiceKeyConstants.ERROR_REQUIRED));
380         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[1].employeeDetails",
381                 RiceKeyConstants.ERROR_REQUIRED));
382         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[2].employeeId",
383                 RiceKeyConstants.ERROR_REQUIRED));
384         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[2].employeeDetails",
385                 RiceKeyConstants.ERROR_REQUIRED));
386 
387     }
388 
389     /**
390      * General test for state based using case constraints and valid characters constraints.
391      *
392      * @throws IOException
393      */
394     @Test
395     public void testStateValidation() throws IOException {
396         Address testAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031", "USA",
397                 null);
398 
399         testAddress.setValidationState("state1");
400         DictionaryValidationResult dictionaryValidationResult = service.validate(testAddress,
401                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
402         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
403         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
404 
405         testAddress.setValidationState("state1");
406         testAddress.setStreet2("@");
407         dictionaryValidationResult = service.validate(testAddress,
408                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
409         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
410         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
411         testAddress.setValidationState("state5");
412         dictionaryValidationResult = service.validate(testAddress,
413                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
414         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
415         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
416 
417         testAddress.setValidationState("state2");
418         testAddress.setCountry("CN");
419         testAddress.setStreet2("Apt 122");
420         dictionaryValidationResult = service.validate(testAddress,
421                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
422         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
423         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
424         testAddress.setValidationState("state5");
425         dictionaryValidationResult = service.validate(testAddress,
426                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
427         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
428         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
429 
430         testAddress.setValidationState("state1");
431         testAddress.setStreet2("");
432         dictionaryValidationResult = service.validate(testAddress,
433                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
434         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
435         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
436         testAddress.setValidationState("state5");
437         dictionaryValidationResult = service.validate(testAddress,
438                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
439         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
440         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
441 
442         testAddress.setValidationState("state2");
443         testAddress.setCountry("USA");
444         testAddress.setStreet2("");
445         dictionaryValidationResult = service.validate(testAddress,
446                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
447         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
448         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
449         testAddress.setValidationState("state5");
450         dictionaryValidationResult = service.validate(testAddress,
451                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
452         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
453         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
454 
455     }
456 
457     /**
458      * Tests for state based validation using a MustOccurs constraint.
459      *
460      * @throws IOException
461      */
462     @Test
463     public void testStateValidationForMustOccurs() throws IOException {
464         Address testAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031", "Country",
465                 null);
466 
467         //Correct address
468         testAddress.setValidationState("state1");
469         DictionaryValidationResult dictionaryValidationResult = service.validate(testAddress,
470                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
471         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
472 
473         testAddress.setValidationState("state2");
474         dictionaryValidationResult = service.validate(testAddress,
475                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
476         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
477 
478         //no error state1, 1 error state2 because mustOccurs applies
479         testAddress.setPostalCode("");
480         testAddress.setState("");
481         testAddress.setValidationState("state1");
482         dictionaryValidationResult = service.validate(testAddress,
483                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
484         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
485 
486         testAddress.setValidationState("state2");
487         dictionaryValidationResult = service.validate(testAddress,
488                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
489         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
490 
491         //Valid for both states
492         testAddress.setPostalCode("");
493         testAddress.setState("CA");
494         testAddress.setValidationState("state1");
495         dictionaryValidationResult = service.validate(testAddress,
496                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
497         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
498 
499         testAddress.setValidationState("state2");
500         dictionaryValidationResult = service.validate(testAddress,
501                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
502         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
503 
504         //Valid for both states
505         testAddress.setPostalCode("23456");
506         testAddress.setState("");
507         testAddress.setValidationState("state1");
508         dictionaryValidationResult = service.validate(testAddress,
509                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
510         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
511 
512         testAddress.setValidationState("state2");
513         dictionaryValidationResult = service.validate(testAddress,
514                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
515         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
516 
517     }
518 
519     /**
520      * Testing of stateConstraintOverrides for multiple different cases
521      *
522      * @throws IOException
523      */
524     @Test
525     public void testStateValidationConstraintOverrides() throws IOException {
526         Address testAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031", "USA",
527                 null);
528 
529         //alphaNumeric
530         testAddress.setStreet2("123AAAAA123");
531         testAddress.setValidationState("state2");
532         DictionaryValidationResult dictionaryValidationResult = service.validate(testAddress,
533                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
534         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
535         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
536 
537         testAddress.setValidationState("state3");
538         dictionaryValidationResult = service.validate(testAddress,
539                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
540         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
541         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
542 
543         testAddress.setValidationState("state4");
544         dictionaryValidationResult = service.validate(testAddress,
545                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
546         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
547         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
548 
549         //Numeric
550         testAddress.setStreet2("1111");
551         testAddress.setValidationState("state2");
552         dictionaryValidationResult = service.validate(testAddress,
553                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
554         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
555         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
556         testAddress.setValidationState("state3");
557         dictionaryValidationResult = service.validate(testAddress,
558                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
559         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
560         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
561         testAddress.setValidationState("state4");
562         dictionaryValidationResult = service.validate(testAddress,
563                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
564         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
565         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
566 
567         //Alpha
568         testAddress.setStreet2("BBBB");
569         testAddress.setValidationState("state2");
570         dictionaryValidationResult = service.validate(testAddress,
571                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
572         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
573         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
574         testAddress.setValidationState("state3");
575         dictionaryValidationResult = service.validate(testAddress,
576                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
577         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
578         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
579         testAddress.setValidationState("state4");
580         dictionaryValidationResult = service.validate(testAddress,
581                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
582         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
583         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
584 
585         //no constraint applies in state5
586         testAddress.setStreet2("$%@");
587         testAddress.setValidationState("state5");
588         dictionaryValidationResult = service.validate(testAddress,
589                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
590         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
591         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
592 
593     }
594 
595     /**
596      * Testing state based validation state ranges, "ie state2>state4" and using prerequisite constraints
597      *
598      * @throws IOException
599      */
600     @Test
601     public void testStateRangeValidationForPrerequisite() throws IOException {
602         Address testAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031", "USA",
603                 null);
604 
605         testAddress.setValidationState("state1");
606         DictionaryValidationResult dictionaryValidationResult = service.validate(testAddress,
607                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
608         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
609 
610         testAddress.setValidationState("state2");
611         dictionaryValidationResult = service.validate(testAddress,
612                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
613         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
614 
615         //state2-state4 should get errors with no country
616         testAddress.setCity("City");
617         testAddress.setCountry("");
618         testAddress.setValidationState("state1");
619         dictionaryValidationResult = service.validate(testAddress,
620                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
621         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
622         testAddress.setValidationState("state2");
623         dictionaryValidationResult = service.validate(testAddress,
624                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
625         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
626         testAddress.setValidationState("state3");
627         dictionaryValidationResult = service.validate(testAddress,
628                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
629         Assert.assertEquals(3, dictionaryValidationResult.getNumberOfErrors());
630         testAddress.setValidationState("state4");
631         dictionaryValidationResult = service.validate(testAddress,
632                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
633         Assert.assertEquals(3, dictionaryValidationResult.getNumberOfErrors());
634         testAddress.setValidationState("state5");
635         dictionaryValidationResult = service.validate(testAddress,
636                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
637         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
638 
639         //should be no errors at any state with both blank
640         testAddress.setCity("");
641         testAddress.setCountry("");
642         testAddress.setValidationState("state1");
643         dictionaryValidationResult = service.validate(testAddress,
644                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
645         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
646         testAddress.setValidationState("state2");
647         dictionaryValidationResult = service.validate(testAddress,
648                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
649         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
650         testAddress.setValidationState("state3");
651         dictionaryValidationResult = service.validate(testAddress,
652                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
653         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
654         testAddress.setValidationState("state4");
655         dictionaryValidationResult = service.validate(testAddress,
656                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
657         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
658         testAddress.setValidationState("state5");
659         dictionaryValidationResult = service.validate(testAddress,
660                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
661         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
662 
663     }
664 
665     @Test
666     public void testStateValidationSimpleConstraintWithOverrides(){
667         Address testAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031", "USA",
668                         null);
669 
670         testAddress.setValidationState("state1");
671         DictionaryValidationResult dictionaryValidationResult = service.validate(testAddress,
672                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
673         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
674 
675         //36 length should apply at state1
676         testAddress.setState("1234567890123456789012345678901234567");
677         dictionaryValidationResult = service.validate(testAddress,
678                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
679         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
680         
681         //correct format for state at state5
682         testAddress.setValidationState("state5");
683         testAddress.setState("DC");
684         dictionaryValidationResult = service.validate(testAddress,
685                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
686         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
687         
688         //state is required at state5 should have error
689         testAddress.setState("");
690         dictionaryValidationResult = service.validate(testAddress,
691                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
692         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
693 
694         //too long
695         testAddress.setState("fff");
696         dictionaryValidationResult = service.validate(testAddress,
697                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
698         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
699 
700         //too short
701         testAddress.setState("f");
702         dictionaryValidationResult = service.validate(testAddress,
703                 "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
704         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
705     }
706 
707     /**
708      * checks whether a {@link DictionaryValidationResult} contains errors for a named attribute
709      *
710      * @param dvr - the dictionary validation result
711      * @param attributeName - the attribute whose validation errors are being checked
712      * @param errorKey - a constant that retrieves an informational message to display to the user
713      * @return true if an error with the error key has been found for the attribute, false otherwise
714      */
715     protected boolean hasError(DictionaryValidationResult dvr, String attributeName, String errorKey) {
716         Iterator<ConstraintValidationResult> dvrIterator = dvr.iterator();
717 
718         boolean containsError = false;
719         while (dvrIterator.hasNext() && !containsError) {
720             ConstraintValidationResult cvr = dvrIterator.next();
721             if (attributeName.contains("[")) {
722                 containsError = attributeName.equals(cvr.getAttributePath())
723                         && errorKey.equals(cvr.getErrorKey())
724                         && ErrorLevel.ERROR == cvr.getStatus();
725             } else {
726                 containsError = attributeName.equals(cvr.getAttributeName())
727                         && errorKey.equals(cvr.getErrorKey())
728                         && ErrorLevel.ERROR == cvr.getStatus();
729             }
730         }
731 
732         return containsError;
733     }
734 
735 }