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   * This class tests the ErrorMap 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 error prepending and lack thereof.
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         // Verify that with putError, the error path is prepended to the propertyName
105         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
106         assertEquals(1, testMap.countFieldMessages("document.newAccountingLine.accountNbr"));
107         assertTrue(testMap.fieldHasMessage("document.newAccountingLine.accountNbr", RiceKeyConstants.ERROR_INACTIVE));
108 
109         testMap.removeAllErrorMessagesForProperty("document.newAccountingLine.accountNbr");
110 
111         // Verify that with putErrorWithoutFullErrorPath, nothing is prepended to the propertyName
112         testMap.putErrorWithoutFullErrorPath("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
113         assertEquals(1, testMap.countFieldMessages("accountNbr"));
114         assertTrue(testMap.fieldHasMessage("accountNbr", RiceKeyConstants.ERROR_INACTIVE));
115         assertFalse(testMap.fieldHasMessage("document.newAccountingLine.accountNbr", RiceKeyConstants.ERROR_INACTIVE));
116 
117         // global key should not be prepended with key path
118         assertTrue(testMap.getKeyPath(KRADConstants.GLOBAL_ERRORS, true).equals(KRADConstants.GLOBAL_ERRORS));
119 
120         assertTrue(testMap.getKeyPath("projectCode.code", true).equals("document.newAccountingLine.projectCode.code"));
121         testMap.removeFromErrorPath("newAccountingLine");
122         assertTrue(testMap.getKeyPath("accountNbr", true).equals("document.accountNbr"));
123         testMap.removeFromErrorPath("document");
124         assertTrue(testMap.getKeyPath("accountNbr", true).equals("accountNbr"));
125 
126     }
127 
128     /**
129      * Test that properties added with errors are being kept.
130      */
131     @Test public void testPropertiesWithErrors() {
132     	MessageMap testMap = new MessageMap();
133 
134         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE);
135         testMap.putError("projectCode", RiceKeyConstants.ERROR_INACTIVE);
136         testMap.putError("chartCode", RiceKeyConstants.ERROR_INACTIVE);
137         testMap.putError("objectCode", RiceKeyConstants.ERROR_INACTIVE);
138         testMap.putError("subAccountNbr", RiceKeyConstants.ERROR_INACTIVE);
139 
140         assertTrue(testMap.getPropertiesWithErrors().contains("accountNbr"));
141         assertTrue(testMap.getPropertiesWithErrors().contains("projectCode"));
142         assertTrue(testMap.getPropertiesWithErrors().contains("chartCode"));
143         assertTrue(testMap.getPropertiesWithErrors().contains("objectCode"));
144         assertTrue(testMap.getPropertiesWithErrors().contains("subAccountNbr"));
145     }
146 
147     /**
148      * Test message parameters are being correctly added and associated with an error message.
149      */
150     @Test public void testMessageParameters() {
151     	MessageMap testMap = new MessageMap();
152 
153         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
154         testMap.putError("accountNbr", RiceKeyConstants.ERROR_REQUIRED, "Account Number");
155         // check duplicate message doesn't get added
156         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
157         testMap.putError("chartCode", RiceKeyConstants.ERROR_REQUIRED, "Chart Code");
158 
159         assertEquals(3, testMap.getErrorCount());
160 
161         AutoPopulatingList errorMessages = testMap.getMessages("accountNbr");
162         assertEquals(2, errorMessages.size());
163         checkMessageParemeters(errorMessages, 0, RiceKeyConstants.ERROR_INACTIVE, new String[] { "Account Number" });
164         checkMessageParemeters(errorMessages, 1, RiceKeyConstants.ERROR_REQUIRED, new String[] { "Account Number" });
165 
166         errorMessages = testMap.getMessages("chartCode");
167         assertEquals(1, errorMessages.size());
168         checkMessageParemeters(errorMessages, 0, RiceKeyConstants.ERROR_REQUIRED, new String[] { "Chart Code" });
169     }
170 
171     private void checkMessageParemeters(AutoPopulatingList errorMessages, int messageIndex, String expectedKeyConstant, String[] expectedParameters) {
172         ErrorMessage message1 = (ErrorMessage) errorMessages.get(messageIndex);
173         assertEquals(expectedKeyConstant, message1.getErrorKey());
174         assertTrue(Arrays.equals(message1.getMessageParameters(), expectedParameters));
175     }
176 
177     /**
178      * Verify that using the same error message multiple times correctly stores different parameters each time. (Reproduces bug
179      * KULNRVSYS-943).
180      */
181     @Test public void testMessageCollisions() {
182         final String PROPERTY_NAME = "document.sourceAccounting*,document.targetAccounting*,newSourceLine*,newTargetLine*";
183         MessageMap testMap = new MessageMap();
184 
185         testMap.putError(PROPERTY_NAME, "error.inactive", "Chart Code");
186         testMap.putError(PROPERTY_NAME, "error.document.subAccountClosed", "Sub-Account Number");
187         testMap.putError(PROPERTY_NAME, "error.inactive", "Object Code");
188         testMap.putError(PROPERTY_NAME, "error.inactive", "SubObject Code");
189         testMap.putError(PROPERTY_NAME, "error.inactive", "Project Code");
190 
191         assertEquals(5, testMap.getErrorCount());
192 
193         // retrieve error messages for the one known key
194         Object thing = testMap.getErrorMessagesForProperty(PROPERTY_NAME);
195 
196         Set usedParams = new HashSet();
197         for (Iterator i = testMap.getAllPropertiesAndErrors().iterator(); i.hasNext();) {
198             Map.Entry entry = (Map.Entry) i.next();
199 
200             String propertyKey = (String) entry.getKey();
201             AutoPopulatingList messageList = (AutoPopulatingList) entry.getValue();
202             for (Iterator j = messageList.iterator(); j.hasNext();) {
203                 ErrorMessage message = (ErrorMessage) j.next();
204 
205                 String[] params = message.getMessageParameters();
206                 if (usedParams.contains(params)) {
207                     fail("usedParams contains duplicate parameters object '" + params + "'");
208                 }
209                 usedParams.add(params);
210             }
211         }
212     }
213 
214     private final static String MIXED_LIST_PATTERN = "document.sourceAccounting*,document.targetAccounting*,foo,bar,newSourceLine*,newTargetLine*";
215 
216     @Test public void testContainsKeyMatchingPattern_mixedList_empty() {
217         assertEquals(false, new MessageMap().containsKeyMatchingPattern(MIXED_LIST_PATTERN));
218     }
219 
220     @Test public void testContainsKeyMatchingPattern_mixedList_simpleNoMatch() {
221     	MessageMap testMap = new MessageMap();
222         testMap.putError("xxx", "error.inactive", "Chart Code");
223         testMap.putError("yyy", "error.inactive", "Chart Code");
224         assertEquals(false, testMap.containsKeyMatchingPattern(MIXED_LIST_PATTERN));
225     }
226 
227     @Test public void testContainsKeyMatchingPattern_mixedList_simpleMatch() {
228     	MessageMap testMap = new MessageMap();
229         testMap.putError("xxx", "error.inactive", "Chart Code");
230         testMap.putError("foo", "error.inactive", "Chart Code");
231         testMap.putError("yyy", "error.inactive", "Chart Code");
232         assertEquals(true, testMap.containsKeyMatchingPattern(MIXED_LIST_PATTERN));
233     }
234 
235     @Test public void testContainsKeyMatchingPattern_mixedList_wildcardMatch() {
236     	MessageMap testMap = new MessageMap();
237         testMap.putError("xxx", "error.inactive", "Chart Code");
238         testMap.putError("document.targetAccountingLine.something", "error.inactive", "Chart Code");
239         testMap.putError("yyy", "error.inactive", "Chart Code");
240         assertEquals(true, testMap.containsKeyMatchingPattern(MIXED_LIST_PATTERN));
241     }
242 
243 
244     @Test public void testReplace_testEquals() {
245         final MessageMap constantMap = buildReplaceErrorMap();
246         MessageMap replaceMap = buildReplaceErrorMap();
247 
248         assertEquals(replaceMap, replaceMap);
249         assertEquals(replaceMap, constantMap);
250         assertEquals(constantMap, replaceMap);
251 
252         replaceMap.putError("somethingElse", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
253 
254         assertFalse(replaceMap.equals(constantMap));
255     }
256 
257 
258     @Test public void testReplace_noMatchingProperty() {
259         final MessageMap constantMap = buildReplaceErrorMap();
260         MessageMap replaceMap = buildReplaceErrorMap();
261 
262         assertTrue(replaceMap.equals(constantMap));
263         assertFalse(replaceMap.containsMessageKey("fooKey"));
264 
265         boolean replaced = replaceMap.replaceError("fooName", "fooKey", "fooReplaceKey");
266         assertFalse(replaced);
267 
268         assertTrue(replaceMap.equals(constantMap));
269         assertFalse(replaceMap.containsMessageKey("fooKey"));
270     }
271 
272     @Test public void testReplace_matchingProperty_noMatchingKey() {
273         final MessageMap constantMap = buildReplaceErrorMap();
274         MessageMap replaceMap = buildReplaceErrorMap();
275 
276         assertTrue(replaceMap.equals(constantMap));
277         assertFalse(replaceMap.containsMessageKey("fooKey"));
278 
279         boolean replaced = replaceMap.replaceError("accountNbr", "fooKey", "fooReplaceKey");
280         assertFalse(replaced);
281 
282         assertTrue(replaceMap.equals(constantMap));
283         assertFalse(replaceMap.containsMessageKey("fooKey"));
284     }
285 
286 
287     @Test public void testReplace_matchingProperty_matchingKey_noParams() {
288         final MessageMap constantMap = buildReplaceErrorMap();
289         MessageMap replaceMap = buildReplaceErrorMap();
290 
291         assertTrue(replaceMap.equals(constantMap));
292         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
293         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
294 
295         AutoPopulatingList preMessages = replaceMap.getMessages("accountNbr");
296         assertEquals(2, preMessages.size());
297 
298         boolean replaced = replaceMap.replaceError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, RiceKeyConstants.ERROR_NOT_AMONG);
299         assertTrue(replaced);
300 
301         assertFalse(replaceMap.equals(constantMap));
302         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
303         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
304 
305         AutoPopulatingList postMessages = replaceMap.getMessages("accountNbr");
306         assertEquals(2, postMessages.size());
307 
308         int replacedCount = 0;
309         for (Iterator i = postMessages.iterator(); i.hasNext();) {
310             ErrorMessage em = (ErrorMessage) i.next();
311             if (em.getErrorKey().equals(RiceKeyConstants.ERROR_NOT_AMONG)) {
312                 String[] params = em.getMessageParameters();
313                 assertEquals(0, params.length);
314 
315                 ++replacedCount;
316             }
317         }
318         assertEquals(1, replacedCount);
319     }
320 
321     @Test public void testReplace_matchingProperty_matchingKey_withParams() {
322         final MessageMap constantMap = buildReplaceErrorMap();
323         MessageMap replaceMap = buildReplaceErrorMap();
324 
325         assertTrue(replaceMap.equals(constantMap));
326         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
327         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
328 
329         AutoPopulatingList preMessages = replaceMap.getMessages("accountNbr");
330         assertEquals(2, preMessages.size());
331 
332         boolean replaced = replaceMap.replaceError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, RiceKeyConstants.ERROR_NOT_AMONG, "zero", "one");
333         assertTrue(replaced);
334 
335         assertFalse(replaceMap.equals(constantMap));
336         assertFalse(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_INACTIVE));
337         assertTrue(replaceMap.containsMessageKey(RiceKeyConstants.ERROR_NOT_AMONG));
338 
339         AutoPopulatingList postMessages = replaceMap.getMessages("accountNbr");
340         assertEquals(2, postMessages.size());
341 
342         int replacedCount = 0;
343         for (Iterator i = postMessages.iterator(); i.hasNext();) {
344             ErrorMessage em = (ErrorMessage) i.next();
345             if (em.getErrorKey().equals(RiceKeyConstants.ERROR_NOT_AMONG)) {
346                 String[] params = em.getMessageParameters();
347                 assertEquals(2, params.length);
348                 assertEquals("zero", params[0]);
349                 assertEquals("one", params[1]);
350 
351                 ++replacedCount;
352             }
353         }
354         assertEquals(1, replacedCount);
355     }
356 
357 
358     private MessageMap buildReplaceErrorMap() {
359     	MessageMap testMap = new MessageMap();
360 
361         testMap.putError("accountNbr", RiceKeyConstants.ERROR_INACTIVE, "Account Number");
362         testMap.putError("accountNbr", RiceKeyConstants.ERROR_REQUIRED, "Account Number");
363         testMap.putError("chartCode", RiceKeyConstants.ERROR_REQUIRED, "Chart Code");
364 
365         return testMap;
366     }
367 }