View Javadoc

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