001    /**
002     * Copyright 2005-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.service.impl;
017    
018    import org.junit.Assert;
019    import org.junit.Before;
020    import org.junit.Test;
021    import org.kuali.rice.krad.test.KRADTestCase;
022    import org.kuali.rice.core.api.util.RiceKeyConstants;
023    import org.kuali.rice.krad.datadictionary.DataDictionary;
024    import org.kuali.rice.krad.datadictionary.DataObjectEntry;
025    import org.kuali.rice.krad.datadictionary.validation.Address;
026    import org.kuali.rice.krad.datadictionary.validation.Company;
027    import org.kuali.rice.krad.datadictionary.validation.Employee;
028    import org.kuali.rice.krad.datadictionary.validation.ErrorLevel;
029    import org.kuali.rice.krad.datadictionary.validation.Person;
030    import org.kuali.rice.krad.datadictionary.validation.constraint.provider.CollectionDefinitionConstraintProvider;
031    import org.kuali.rice.krad.datadictionary.validation.processor.MustOccurConstraintProcessor;
032    import org.kuali.rice.krad.datadictionary.validation.result.ConstraintValidationResult;
033    import org.kuali.rice.krad.datadictionary.validation.result.DictionaryValidationResult;
034    import org.kuali.rice.krad.service.DataDictionaryService;
035    import org.springframework.context.support.ClassPathXmlApplicationContext;
036    
037    import java.io.IOException;
038    import java.util.ArrayList;
039    import java.util.Date;
040    import java.util.Iterator;
041    import java.util.List;
042    
043    /**
044     * DictionaryValidationServiceImplTest tests {@link DictionaryValidationServiceImpl} using the data dictionary
045     * configurations in
046     * org/kuali/rice/krad/test/datadictionary/validation
047     *
048     * @author Kuali Rice Team (rice.collab@kuali.org)
049     */
050    public class DictionaryValidationServiceImplTest extends KRADTestCase {
051    
052        ClassPathXmlApplicationContext context;
053        private DictionaryValidationServiceImpl service;
054        DataDictionary dataDictionary = new DataDictionary();
055    
056        protected DataObjectEntry addressEntry;
057    
058        private Address validLondonAddress = new Address("8129 Maiden Lane", "", "London", "", "SE1 0P3", "UK", null);
059        private Address validUSAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031",
060                "USA", null);
061        private Address invalidUSAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "",
062                "92342-123456", "USA", null);
063        private Address noZipNoCityUSAddress = new Address("893 Presidential Ave", "Suite 800", null, "DC", null, "USA",
064                null);
065        private Address validNonDCUSAddress = new Address("89 11th Street", "Suite 800", "Seattle", "WA", "", "USA", null);
066        private Address invalidDCUSAddress = new Address("89 Presidential Ave", "Suite 800", "Washington", "DC", "12031",
067                "USA", null);
068        private Address invalidHKAddress = new Address("182 Lin Pai Road", "", "Hong Kong", "N.T.", "", "CN", null);
069    
070        @Before
071        public void setUp() throws Exception {
072            super.setUp();
073    
074            context = new ClassPathXmlApplicationContext("classpath:DictionaryValidationServiceSpringBeans.xml");
075    
076            service = (DictionaryValidationServiceImpl) context.getBean("dictionaryValidationService");
077    
078            dataDictionary.addConfigFileLocation("KR-NS",
079                    "classpath:org/kuali/rice/krad/datadictionary/DataDictionaryBaseTypes.xml");
080            dataDictionary.addConfigFileLocation("KR-NS",
081                    "classpath:org/kuali/rice/kns/bo/datadictionary/DataDictionaryBaseTypes.xml");
082            dataDictionary.addConfigFileLocation("KR-NS",
083                    "classpath:org/kuali/rice/krad/test/datadictionary/validation/Company.xml");
084            dataDictionary.addConfigFileLocation("KR-NS",
085                    "classpath:org/kuali/rice/krad/test/datadictionary/validation/Address.xml");
086            dataDictionary.addConfigFileLocation("KR-NS",
087                    "classpath:org/kuali/rice/krad/test/datadictionary/validation/Employee.xml");
088            dataDictionary.addConfigFileLocation("KR-NS","classpath:org/kuali/rice/krad/test/datadictionary/validation/Person.xml");
089    
090            dataDictionary.parseDataDictionaryConfigurationFiles(false);
091    
092            addressEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Address");
093        }
094    
095        @Test
096        /**
097         * tests that a valid non US address will not generate warnings or errors
098         *
099         * @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    }