View Javadoc

1   /**
2    * Copyright 2005-2013 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.util;
17  
18  import org.junit.Test;
19  import org.kuali.rice.core.api.util.RiceKeyConstants;
20  import org.springframework.util.AutoPopulatingList;
21  
22  import java.util.Arrays;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import static org.junit.Assert.*;
29  
30  /**
31   * MessageMapTest tests the MessageMap methods
32   *
33   * @author Kuali Rice Team (rice.collab@kuali.org)
34   */
35  public class MessageMapTest {
36  
37      /**
38       * ErrorMap should only allow String keys and values.
39       */
40      @Test public void testPut() {
41          MessageMap testMap = new MessageMap();
42  
43          // should be ok putting strings
44          try {
45              testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
46          }
47          catch (RuntimeException e) {
48              fail("ErrorMap threw exception adding string pair");
49          }
50      }
51  
52      /**
53       * Test all errors are getting added and counted correctly.
54       */
55      @Test public void testErrorCount() {
56      	MessageMap testMap = new MessageMap();
57  
58          testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
59          assertTrue(testMap.getErrorCount() == 1);
60  
61          testMap.putError("accountNbr", RiceKeyConstants.ERROR_INVALID_FORMAT);
62          assertTrue(testMap.getErrorCount() == 2);
63  
64          testMap.putError("chartCode", RiceKeyConstants.ERROR_INVALID_FORMAT);
65          testMap.putError("projectCode", RiceKeyConstants.ERROR_INVALID_FORMAT);
66          testMap.putError("objectCode", RiceKeyConstants.ERROR_INVALID_FORMAT);
67          assertTrue(testMap.getErrorCount() == 5);
68  
69          testMap.removeAllErrorMessagesForProperty("accountNbr");
70          assertTrue(testMap.getErrorCount() == 3);
71      }
72  
73      /**
74       * Test messages are getting accumulated correctly for a property.
75       */
76      @Test public void testFieldMessages() {
77      	MessageMap testMap = new MessageMap();
78  
79          testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
80          testMap.putError("accountNbr", RiceKeyConstants.ERROR_INVALID_FORMAT);
81          testMap.putError("accountNbr", RiceKeyConstants.ERROR_PHONE_NUMBER);
82          assertEquals(3, testMap.countFieldMessages("accountNbr"));
83          assertTrue(testMap.fieldHasMessage("accountNbr", RiceKeyConstants.ERROR_INACTIVE));
84          assertTrue(testMap.fieldHasMessage("accountNbr", RiceKeyConstants.ERROR_INVALID_FORMAT));
85          assertTrue(testMap.fieldHasMessage("accountNbr", RiceKeyConstants.ERROR_PHONE_NUMBER));
86      }
87  
88      /**
89       * Test error prepending and lack thereof.
90       */
91      @Test public void testErrorPath() {
92      	MessageMap testMap = new MessageMap();
93  
94          assertTrue(testMap.getKeyPath("accountNbr", true).equals("accountNbr"));
95          testMap.addToErrorPath("document");
96          assertTrue(testMap.getKeyPath("accountNbr", true).equals("document.accountNbr"));
97          assertTrue(testMap.getKeyPath("accountNbr", false).equals("accountNbr"));
98          testMap.removeFromErrorPath("document");
99          assertTrue(testMap.getKeyPath("accountNbr", true).equals("accountNbr"));
100         assertTrue(testMap.getKeyPath("accountNbr", false).equals("accountNbr"));
101         testMap.addToErrorPath("document");
102         testMap.addToErrorPath("newAccountingLine");
103         assertTrue(testMap.getKeyPath("accountNbr", true).equals("document.newAccountingLine.accountNbr"));
104         assertTrue(testMap.getKeyPath("accountNbr", false).equals("accountNbr"));
105 
106         // Verify that with putError, the error path is prepended to the propertyName
107         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
108         assertEquals(1, testMap.countFieldMessages("document.newAccountingLine.accountNbr"));
109         assertTrue(testMap.fieldHasMessage("document.newAccountingLine.accountNbr", RiceKeyConstants.ERROR_INACTIVE));
110 
111         testMap.removeAllErrorMessagesForProperty("document.newAccountingLine.accountNbr");
112 
113         // Verify that with putErrorWithoutFullErrorPath, nothing is prepended to the propertyName
114         testMap.putErrorWithoutFullErrorPath("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
115         assertEquals(1, testMap.countFieldMessages("accountNbr"));
116         assertTrue(testMap.fieldHasMessage("accountNbr", RiceKeyConstants.ERROR_INACTIVE));
117         assertFalse(testMap.fieldHasMessage("document.newAccountingLine.accountNbr", RiceKeyConstants.ERROR_INACTIVE));
118 
119         // global key should not be prepended with key path
120         assertTrue(testMap.getKeyPath(KRADConstants.GLOBAL_ERRORS, true).equals(KRADConstants.GLOBAL_ERRORS));
121 
122         assertTrue(testMap.getKeyPath("projectCode.code", true).equals("document.newAccountingLine.projectCode.code"));
123         testMap.removeFromErrorPath("newAccountingLine");
124         assertTrue(testMap.getKeyPath("accountNbr", true).equals("document.accountNbr"));
125         testMap.removeFromErrorPath("document");
126         assertTrue(testMap.getKeyPath("accountNbr", true).equals("accountNbr"));
127 
128     }
129 
130     /**
131      * Test that properties added with errors are being kept.
132      */
133     @Test public void testPropertiesWithErrors() {
134     	MessageMap testMap = new MessageMap();
135 
136         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
137         testMap.putError("projectCode", RiceKeyConstants.ERROR_INACTIVE);
138         testMap.putError("chartCode", RiceKeyConstants.ERROR_INACTIVE);
139         testMap.putError("objectCode", RiceKeyConstants.ERROR_INACTIVE);
140         testMap.putError("subAccountNbr", RiceKeyConstants.ERROR_INACTIVE);
141 
142         assertTrue(testMap.getPropertiesWithErrors().contains("accountNbr"));
143         assertTrue(testMap.getPropertiesWithErrors().contains("projectCode"));
144         assertTrue(testMap.getPropertiesWithErrors().contains("chartCode"));
145         assertTrue(testMap.getPropertiesWithErrors().contains("objectCode"));
146         assertTrue(testMap.getPropertiesWithErrors().contains("subAccountNbr"));
147     }
148 
149     /**
150      * Test message parameters are being correctly added and associated with an error message.
151      */
152     @Test public void testMessageParameters() {
153     	MessageMap testMap = new MessageMap();
154 
155         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
156         testMap.putError("accountNbr", RiceKeyConstants.ERROR_REQUIRED, "Account Number");
157         // check duplicate message doesn't get added
158         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
159         testMap.putError("chartCode", RiceKeyConstants.ERROR_REQUIRED, "Chart Code");
160 
161         assertEquals(3, testMap.getErrorCount());
162 
163         AutoPopulatingList errorMessages = testMap.getMessages("accountNbr");
164         assertEquals(2, errorMessages.size());
165         checkMessageParemeters(errorMessages, 0, RiceKeyConstants.ERROR_INACTIVE, new String[] { "Account Number" });
166         checkMessageParemeters(errorMessages, 1, RiceKeyConstants.ERROR_REQUIRED, new String[] { "Account Number" });
167 
168         errorMessages = testMap.getMessages("chartCode");
169         assertEquals(1, errorMessages.size());
170         checkMessageParemeters(errorMessages, 0, RiceKeyConstants.ERROR_REQUIRED, new String[] { "Chart Code" });
171     }
172 
173     private void checkMessageParemeters(AutoPopulatingList errorMessages, int messageIndex, String expectedKeyConstant, String[] expectedParameters) {
174         ErrorMessage message1 = (ErrorMessage) errorMessages.get(messageIndex);
175         assertEquals(expectedKeyConstant, message1.getErrorKey());
176         assertTrue(Arrays.equals(message1.getMessageParameters(), expectedParameters));
177     }
178 
179     /**
180      * Verify that using the same error message multiple times correctly stores different parameters each time. (Reproduces bug
181      * KULNRVSYS-943).
182      */
183     @Test public void testMessageCollisions() {
184         final String PROPERTY_NAME = "document.sourceAccounting*,document.targetAccounting*,newSourceLine*,newTargetLine*";
185         MessageMap testMap = new MessageMap();
186 
187         testMap.putError(PROPERTY_NAME, "error.inactive", "Chart Code");
188         testMap.putError(PROPERTY_NAME, "error.document.subAccountClosed", "Sub-Account Number");
189         testMap.putError(PROPERTY_NAME, "error.inactive", "Object Code");
190         testMap.putError(PROPERTY_NAME, "error.inactive", "SubObject Code");
191         testMap.putError(PROPERTY_NAME, "error.inactive", "Project Code");
192 
193         assertEquals(5, testMap.getErrorCount());
194 
195         // retrieve error messages for the one known key
196         Object thing = testMap.getErrorMessagesForProperty(PROPERTY_NAME);
197 
198         Set usedParams = new HashSet();
199         for (Iterator i = testMap.getAllPropertiesAndErrors().iterator(); i.hasNext();) {
200             Map.Entry entry = (Map.Entry) i.next();
201 
202             String propertyKey = (String) entry.getKey();
203             AutoPopulatingList messageList = (AutoPopulatingList) entry.getValue();
204             for (Iterator j = messageList.iterator(); j.hasNext();) {
205                 ErrorMessage message = (ErrorMessage) j.next();
206 
207                 String[] params = message.getMessageParameters();
208                 if (usedParams.contains(params)) {
209                     fail("usedParams contains duplicate parameters object '" + params + "'");
210                 }
211                 usedParams.add(params);
212             }
213         }
214     }
215 
216     private final static String MIXED_LIST_PATTERN = "document.sourceAccounting*,document.targetAccounting*,foo,bar,newSourceLine*,newTargetLine*";
217 
218     /**
219      * test that the given list of keys do not exist in an empty message map
220      */
221     @Test public void testContainsKeyMatchingPattern_mixedList_empty() {
222         assertEquals(false, new MessageMap().containsKeyMatchingPattern(MIXED_LIST_PATTERN));
223     }
224 
225     /**
226      * test that the given list of keys do not exist in the message map
227      */
228     @Test public void testContainsKeyMatchingPattern_mixedList_simpleNoMatch() {
229     	MessageMap testMap = new MessageMap();
230         testMap.putError("xxx", "error.inactive", "Chart Code");
231         testMap.putError("yyy", "error.inactive", "Chart Code");
232         assertEquals(false, testMap.containsKeyMatchingPattern(MIXED_LIST_PATTERN));
233     }
234 
235     /**
236      * test that one of the non-wildcard keys in the given list is found in the message map
237      */
238     @Test public void testContainsKeyMatchingPattern_mixedList_simpleMatch() {
239     	MessageMap testMap = new MessageMap();
240         testMap.putError("xxx", "error.inactive", "Chart Code");
241         testMap.putError("foo", "error.inactive", "Chart Code");
242         testMap.putError("yyy", "error.inactive", "Chart Code");
243         assertEquals(true, testMap.containsKeyMatchingPattern(MIXED_LIST_PATTERN));
244     }
245 
246     /**
247      * test that one of the wildcard keys in the given list is found in the message map
248      */
249     @Test public void testContainsKeyMatchingPattern_mixedList_wildcardMatch() {
250     	MessageMap testMap = new MessageMap();
251         testMap.putError("xxx", "error.inactive", "Chart Code");
252         testMap.putError("document.targetAccountingLine.something", "error.inactive", "Chart Code");
253         testMap.putError("yyy", "error.inactive", "Chart Code");
254         assertEquals(true, testMap.containsKeyMatchingPattern(MIXED_LIST_PATTERN));
255     }
256 
257     /**
258      * tests that two message maps are not equal when an additional message is added to one
259      */
260     @Test public void testReplace_testEquals() {
261         final MessageMap constantMap = buildReplaceErrorMap();
262         MessageMap replaceMap = buildReplaceErrorMap();
263 
264         assertEquals(replaceMap, replaceMap);
265         assertEquals(replaceMap, constantMap);
266         assertEquals(constantMap, replaceMap);
267 
268         replaceMap.putError("somethingElse", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
269 
270         assertFalse(replaceMap.equals(constantMap));
271     }
272 
273     /**
274      * test that a none existent key and none existent property are not replaceable in the message map
275      */
276     @Test public void testReplace_noMatchingProperty() {
277         final MessageMap constantMap = buildReplaceErrorMap();
278         MessageMap replaceMap = buildReplaceErrorMap();
279 
280         assertTrue(replaceMap.equals(constantMap));
281         assertFalse(replaceMap.containsMessageKey("fooKey"));
282 
283         boolean replaced = replaceMap.replaceError("fooName", "fooKey", "fooReplaceKey");
284         assertFalse(replaced);
285 
286         assertTrue(replaceMap.equals(constantMap));
287         assertFalse(replaceMap.containsMessageKey("fooKey"));
288     }
289 
290     /**
291      * test that a none existent key and existing property are not replaceable in the message map
292      */
293     @Test public void testReplace_matchingProperty_noMatchingKey() {
294         final MessageMap constantMap = buildReplaceErrorMap();
295         MessageMap replaceMap = buildReplaceErrorMap();
296 
297         assertTrue(replaceMap.equals(constantMap));
298         assertFalse(replaceMap.containsMessageKey("fooKey"));
299 
300         boolean replaced = replaceMap.replaceError("accountNbr", "fooKey", "fooReplaceKey");
301         assertFalse(replaced);
302 
303         assertTrue(replaceMap.equals(constantMap));
304         assertFalse(replaceMap.containsMessageKey("fooKey"));
305     }
306 
307     /**
308      * test that an existing key and existing property are replaced in the message map
309      */
310     @Test public void testReplace_matchingProperty_matchingKey_noParams() {
311         final MessageMap constantMap = buildReplaceErrorMap();
312         MessageMap replaceMap = buildReplaceErrorMap();
313 
314         assertTrue(replaceMap.equals(constantMap));
315         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
316         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
317 
318         AutoPopulatingList preMessages = replaceMap.getMessages("accountNbr");
319         assertEquals(2, preMessages.size());
320 
321         boolean replaced = replaceMap.replaceError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, RiceKeyConstants.ERROR_NOT_AMONG);
322         assertTrue(replaced);
323 
324         assertFalse(replaceMap.equals(constantMap));
325         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
326         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
327 
328         AutoPopulatingList postMessages = replaceMap.getMessages("accountNbr");
329         assertEquals(2, postMessages.size());
330 
331         int replacedCount = 0;
332         for (Iterator i = postMessages.iterator(); i.hasNext();) {
333             ErrorMessage em = (ErrorMessage) i.next();
334             if (em.getErrorKey().equals(RiceKeyConstants.ERROR_NOT_AMONG)) {
335                 String[] params = em.getMessageParameters();
336                 assertEquals(0, params.length);
337 
338                 ++replacedCount;
339             }
340         }
341         assertEquals(1, replacedCount);
342     }
343 
344     /**
345      * test that an existing key and existing property are replaced in the message map along with the associated params
346      */
347     @Test public void testReplace_matchingProperty_matchingKey_withParams() {
348         final MessageMap constantMap = buildReplaceErrorMap();
349         MessageMap replaceMap = buildReplaceErrorMap();
350 
351         assertTrue(replaceMap.equals(constantMap));
352         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
353         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
354 
355         AutoPopulatingList preMessages = replaceMap.getMessages("accountNbr");
356         assertEquals(2, preMessages.size());
357 
358         boolean replaced = replaceMap.replaceError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, RiceKeyConstants.ERROR_NOT_AMONG, "zero", "one");
359         assertTrue(replaced);
360 
361         assertFalse(replaceMap.equals(constantMap));
362         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
363         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
364 
365         AutoPopulatingList postMessages = replaceMap.getMessages("accountNbr");
366         assertEquals(2, postMessages.size());
367 
368         int replacedCount = 0;
369         for (Iterator i = postMessages.iterator(); i.hasNext();) {
370             ErrorMessage em = (ErrorMessage) i.next();
371             if (em.getErrorKey().equals(RiceKeyConstants.ERROR_NOT_AMONG)) {
372                 String[] params = em.getMessageParameters();
373                 assertEquals(2, params.length);
374                 assertEquals("zero", params[0]);
375                 assertEquals("one", params[1]);
376 
377                 ++replacedCount;
378             }
379         }
380         assertEquals(1, replacedCount);
381     }
382 
383     /**
384      * create a test error map
385      *
386      * @return a MessageMap with test entries
387      */
388     private MessageMap buildReplaceErrorMap() {
389     	MessageMap testMap = new MessageMap();
390 
391         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
392         testMap.putError("accountNbr", RiceKeyConstants.ERROR_REQUIRED, "Account Number");
393         testMap.putError("chartCode", RiceKeyConstants.ERROR_REQUIRED, "Chart Code");
394 
395         return testMap;
396     }
397 }