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