View Javadoc

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