View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.convert;
20  
21  import java.util.Locale;
22  
23  import javax.faces.convert.ConverterException;
24  import javax.faces.convert.NumberConverter;
25  import javax.faces.component.UIComponent;
26  
27  import org.apache.myfaces.trinidad.convert.ConverterTestCase;
28  import org.apache.myfaces.trinidadbuild.test.MockUIComponentWrapper;
29  import org.apache.shale.test.mock.MockFacesContext;
30  import org.jmock.Mock;
31  
32  /**
33   * Test NumberConverter
34   * @version $Name: $ ($version: $) $Date: 16-aug-2005.15:12:23 $
35   */
36  public abstract class NumberConverterTestCase extends ConverterTestCase
37  {
38    public NumberConverterTestCase(String name)
39    {
40      super(name);
41    }
42  
43    /**
44     * Test when context is set to null
45     */
46    public void testNullContext()
47    {
48      Mock mock = mock(UIComponent.class);
49      UIComponent component = (UIComponent) mock.proxy();
50      //we do not care about getValueExpression() being called or not
51      mock.stubs().method("getValueExpression");
52  
53      MockUIComponentWrapper wrapper = new MockUIComponentWrapper(mock, component);
54      NumberConverter converter = getNumberConverter();
55  
56      doTestNullContext(wrapper, converter);
57    }
58  
59    public void testNullComponent()
60    {
61      NumberConverter converter  = getNumberConverter();
62  
63      doTestNullComponent(facesContext, converter);
64    }
65  
66    /**
67     * Tests that null returns immediately.
68     *
69     * @throws ConverterException  when test fails
70     */
71    public void testNullInputValue() throws ConverterException
72    {
73      Mock mock = mock(UIComponent.class);
74      UIComponent component = (UIComponent) mock.proxy();
75      //we do not care about getValueExpression() being called or not
76      mock.stubs().method("getValueExpression");
77  
78      MockUIComponentWrapper wrapper = new MockUIComponentWrapper(mock, component);
79      NumberConverter converter  = getNumberConverter();
80  
81      doTestNull(facesContext, wrapper, converter);
82    }
83  
84    public void testEmptyValueConversion()
85    {
86      super.doTestBlankValue(getNumberConverter());
87    }
88  
89    public void testValueType()
90    {
91      Mock mock = mock(UIComponent.class);
92      UIComponent component = (UIComponent) mock.proxy();
93      //we do not care about getValueExpression() being called or not
94      mock.stubs().method("getValueExpression");
95  
96      setFacesContext(facesContext);
97      try
98      {
99        String input = "123";
100       NumberConverter converter = getNumberConverter();
101       Object number = converter.getAsObject(facesContext, component, input);
102       assertEquals(true, number instanceof Number);
103       assertEquals(true, (((Number)number).intValue() == 123));
104 
105       String outVal = converter.getAsString(facesContext, component, number);
106       assertEquals(input, outVal);
107     }
108     finally
109     {
110       setFacesContext(null);
111     }
112     mock.verify();
113   }
114 
115   public void testAppropriateFormatsArePicked()
116   {
117     // check if appropriate formtas based on the types are chosen.
118     // like numeric, currency, percent are picked. Chose pattern if set avoiding
119     // types
120 
121     String[] patterns = {"##,##",null, null, null,null};
122 
123     //pick pattern, numeric, percent, currency
124     String[] types = {null,"number", "percent", "currency", "currency"};
125     String[] inputValues = {"99,99","99", "99%","$99", "$99.00"} ;
126     Number[] expectedValues = {new Long(9999), new Long(99), new Double(0.99), new Long(99), new Long(99)};
127     String[] expectedStringValues = {"99,99","99", "99%","$99.00", "$99.00"} ;
128     Locale usLocl = Locale.US;
129     Locale[] locales = {usLocl, usLocl, usLocl, usLocl,Locale.CANADA};
130 
131     NumberConverter nconv = getNumberConverter();
132 
133     for (int i = 0; i < patterns.length; i++)
134     {
135       Mock mock = mock(UIComponent.class);
136       UIComponent component = (UIComponent) mock.proxy();
137       //we do not care about getValueExpression() being called or not
138       mock.stubs().method("getValueExpression");
139 
140 
141       setFacesContext(facesContext);
142       try
143       {
144         nconv.setPattern(patterns[i]);
145         nconv.setType(types[i]);
146         nconv.setLocale(locales[i]);
147         
148         Object convValue = nconv.getAsObject(facesContext, component, inputValues[i]);
149         
150         // Trinidad does BigDecimal, for some reasons.
151         // see TRINIDAD-1124
152         if(i==2)
153         {
154           convValue = ((Number) convValue).doubleValue();
155         }
156         else
157         {
158           convValue = ((Number) convValue).longValue();
159         }
160 
161         assertEquals(expectedValues[i], convValue);
162         
163         String outValue = nconv.getAsString(facesContext, component, expectedValues[i]);
164         
165         assertEquals(expectedStringValues[i], outValue);
166       }
167       finally
168       {
169         setFacesContext(null);
170       }
171       mock.verify();
172     }
173   }
174 
175   public void testStateHolderSaveRestore()
176   {
177     NumberConverter converter = getNumberConverter();
178 
179     NumberConverter restoreConverter = getNumberConverter();
180     Mock mock = mock(UIComponent.class);
181     UIComponent component = (UIComponent) mock.proxy();
182     //we do not care about getValueExpression() being called or not
183     mock.stubs().method("getValueExpression");
184 
185     MockUIComponentWrapper wrapper = new MockUIComponentWrapper(mock, component);
186 
187     for (int i = 0; i < _LOCALES.length; i++)
188     {
189       converter.setLocale(_LOCALES[i]);
190       restoreConverter.setLocale(_LOCALES[i]);
191       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
192 
193       converter.setCurrencyCode( _CURRENCY_CODES[i]);
194       restoreConverter.setCurrencyCode( _CURRENCY_CODES[i]);
195       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
196 
197       converter.setCurrencySymbol(_CURRENCY_SYMBOLS[i]);
198       restoreConverter.setCurrencySymbol(_CURRENCY_SYMBOLS[i]);
199       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
200 
201       converter.setIntegerOnly(_INTEGER_ONLY[1]);
202       restoreConverter.setIntegerOnly(_INTEGER_ONLY[1]);
203       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
204 
205       converter.setMaxFractionDigits(_MAX_FRACTION_DIGITS[i]);
206       restoreConverter.setMaxFractionDigits(_MAX_FRACTION_DIGITS[i]);
207       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
208 
209       converter.setMaxIntegerDigits(_MAX_INT_DIGITS[i]);
210       restoreConverter.setMaxIntegerDigits(_MAX_INT_DIGITS[i]);
211       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
212 
213       converter.setMinFractionDigits(_MIN_FRACT_DIGITS[i]);
214       restoreConverter.setMinFractionDigits(_MIN_FRACT_DIGITS[i]);
215       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
216 
217       converter.setMinIntegerDigits(_MIN_INT_DIGITS[i]);
218       restoreConverter.setMinIntegerDigits(_MIN_INT_DIGITS[i]);
219       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
220 
221       converter.setPattern( _PATTTERNS[i]);
222       restoreConverter.setPattern(_PATTTERNS[i]);
223       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
224 
225       converter.setTransient(_TRANSIENT[i]);
226       restoreConverter.setTransient(_TRANSIENT[i]);
227       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
228 
229       converter.setType(_TYPES[i]);
230       doTestStateHolderSaveRestore(converter, restoreConverter, facesContext, wrapper);
231 
232     }
233   }
234 
235 
236   
237   public void testCurrencyCodeIsHonoured()
238   {
239     NumberConverter converter = getNumberConverter();
240     Mock mock = mock(UIComponent.class);
241     UIComponent component = (UIComponent) mock.proxy();
242     //we do not care about getValueExpression() being called or not
243     mock.stubs().method("getValueExpression");
244 
245     converter.setLocale(Locale.US);
246     converter.setType("currency");
247     Double  value = new Double(99);
248 
249     setFacesContext(facesContext);
250     try
251     {
252       String outPut = converter.getAsString(facesContext, component, value);
253       assertEquals("$99.00", outPut);
254       //Locale is US. By general convention the output prefix would be '$'
255       // since we set the currency code to 'DEM' value should be DEM[value]
256       converter.setCurrencyCode("DEM");
257       
258       outPut = converter.getAsString(facesContext, component, value);
259       assertEquals("DEM99.00", outPut);
260     }
261     finally
262     {
263       setFacesContext(null);
264     }
265     mock.verify();
266   }
267 
268   public void testCurrencyCodeIsHonouredWhenCurrencyCodeAndCurrencySymbolIsSet()
269   {
270     NumberConverter converter   = getNumberConverter();
271     Mock mock = buildMockUIComponent(2);
272     UIComponent component = (UIComponent) mock.proxy();
273     //we do not care about getValueExpression() being called or not
274     mock.stubs().method("getValueExpression");
275 
276     converter.setLocale(Locale.US);
277     converter.setType("currency");
278     Double value = new Double(99);
279 
280     setFacesContext(facesContext);
281     try
282     {
283       String outPut = converter.getAsString(facesContext, component, value);
284       assertEquals("$99.00", outPut);
285       //Locale is US. By general convention the output prefix would be '$'
286       // since we set the currency code to 'DEM' value should be DEM[value]
287       converter.setCurrencyCode("DEM");
288       
289       // Let us set the symbol to '*'. This should not take effect, since currency
290       // code is set.
291       converter.setCurrencySymbol("*");
292       
293       outPut = converter.getAsString(facesContext, component, value);
294       assertEquals("DEM99.00", outPut);
295       try
296       {
297         Number outValue = (Number)converter.getAsObject(facesContext, component, "DEM99.00");
298         // FIXME =-= AdamWiner:  this is not reporting an error as of
299         // JSF 1.2 - should it?
300         //        fail("Exception should occur - since currency should not be considered while formatting");
301       }
302       catch(Exception e)
303       {
304         ;//Expected to fail.
305       }
306     }
307     finally
308     {
309       setFacesContext(null);
310     }
311     mock.verify();
312   }
313 
314   public void testCurrencySymbolIsHonoured()
315   {
316     NumberConverter converter = getNumberConverter();
317     Mock mock = mock(UIComponent.class);
318     UIComponent component = (UIComponent) mock.proxy();
319     //we do not care about getValueExpression() being called or not
320     mock.stubs().method("getValueExpression");
321 
322     converter.setLocale(Locale.US);
323     converter.setType("currency");
324     Double  value = new Double(99);
325     //Locale is US. By general convention the output prefix would be '$'
326     // since we set currency symbol to '*' we should get the value to be *99.00
327     converter.setCurrencySymbol("*");
328     
329     setFacesContext(facesContext);
330     try
331     {
332       String outPut = converter.getAsString(facesContext, component, value);
333       assertEquals("*99.00", outPut);
334     }
335     finally
336     {
337       setFacesContext(null);
338     }
339     mock.verify();
340   }
341 
342   public void testIntegerOnlyIsHonoured()
343   {
344     // integerOnly is used only while parsing to create number objects
345     NumberConverter converter = getNumberConverter();
346     Mock mock = mock(UIComponent.class);
347     UIComponent component = (UIComponent) mock.proxy();
348     //we do not care about getValueExpression() being called or not
349     mock.stubs().method("getValueExpression");
350 
351     converter.setLocale(Locale.US);
352 
353     String[] inputs = {"23.10", "44.90876", "11111", "67859.0001"};
354     Number[] expectedValues = {new Long(23), new Long(44), new Long(11111), new Long(67859)};
355 
356     setFacesContext(facesContext);
357     try
358     {
359       for (int i = 0; i < inputs.length; i++)
360       {
361         converter.setIntegerOnly(true);
362         Number num = (Number) converter.getAsObject(facesContext, component, inputs[i]);
363         assertEquals(expectedValues[i], num);
364       }
365     }
366     finally
367     {
368       setFacesContext(null);
369     }
370     mock.verify();
371   }
372 
373 
374   public void testSettingFractDigitsAndSettingMinDigitsDoesNotAffectParsing()
375   {
376     // integerOnly is used only while parsing to create number objects
377     NumberConverter converter = getNumberConverter();
378     Mock mock = mock(UIComponent.class);
379     UIComponent component = (UIComponent) mock.proxy();
380     //we do not care about getValueExpression() being called or not
381     mock.stubs().method("getValueExpression");
382 
383     converter.setLocale(Locale.US);
384 
385     String[] inputs = {"23.10", "44.90876", "11111", "67859.0001"};
386     Number[] expectedValues = {new Long(23), new Long(44), new Long(11111), new Long(67859)};
387 
388     setFacesContext(facesContext);
389     try
390     {
391       for (int i = 0; i < inputs.length; i++)
392       {
393         // setting these values should not affect parsing.
394         converter.setMaxFractionDigits(10);
395         converter.setMaxIntegerDigits(1);
396         converter.setMinFractionDigits(1);
397         converter.setMinFractionDigits(0);
398         
399         // this should be taken care by the parsing code
400         converter.setIntegerOnly(true);
401         Number num = (Number) converter.getAsObject(facesContext, component, inputs[i]);
402         assertEquals(expectedValues[i], num);
403       }
404     }
405     finally
406     {
407       setFacesContext(null);
408     }
409     mock.verify();
410   }
411 
412   public void testLocaleIsPickedUpFromViewRoot()
413   {
414 
415     NumberConverter converter = getNumberConverter();
416     Mock mock = mock(UIComponent.class);
417     UIComponent component = (UIComponent) mock.proxy();
418     //we do not care about getValueExpression() being called or not
419     mock.stubs().method("getValueExpression");
420 
421     String input = "1234.56";
422 
423     setFacesContext(facesContext);
424     facesContext.getViewRoot().setLocale(Locale.US);
425 
426     try
427     {
428       // if we get a valid object, implies locale was indeed picked up.
429       // otherwise we would have got a null pointer exception or other exception
430       Object value = converter.getAsObject(facesContext, component, input);
431       assertEquals(new Double(1234.56), ((Number)value).doubleValue());
432     }
433     finally
434     {
435       setFacesContext(null);
436     }
437   }
438 
439   public void testGroupingIsHonoured()
440   {
441     Number[] inputValues = {new Long(9999), new Long(99), new Double(0.99), new Double(99999.567), new Long(9999)};
442     boolean [] isGroupingUsed = {true, true, true, false, false };
443     String[] expectedValues = {"9,999", "99", "0.99", "99999.567", "9999"};
444 
445     NumberConverter converter = getNumberConverter();
446     Mock mock = mock(UIComponent.class);
447     UIComponent component = (UIComponent) mock.proxy();
448     //we do not care about getValueExpression() being called or not
449     mock.stubs().method("getValueExpression");
450 
451     converter.setLocale(Locale.US);
452     setFacesContext(facesContext);
453     try
454     {
455       for (int i = 0; i < inputValues.length; i++)
456       {
457         converter.setGroupingUsed(isGroupingUsed[i]);
458         String out = converter.getAsString(facesContext, component, inputValues[i]);
459         assertEquals(expectedValues[i], out);
460       }
461     }
462     finally
463     {
464       setFacesContext(null);
465     }
466     mock.verify();
467   }
468 
469   public void testStrictnessOfConversion()
470   {
471     String[] inputValues = {"123ABC", "22.22.2" };
472     Mock mock = buildMockUIComponent(inputValues.length * 3);
473     UIComponent component = (UIComponent) mock.proxy();
474     //we do not care about getValueExpression() being called or not
475     mock.stubs().method("getValueExpression");
476 
477     MockUIComponentWrapper wrapper = new MockUIComponentWrapper(mock, component);
478 
479     for (int i = 0; i < inputValues.length; i++)
480     {
481       doTestStrictNess(facesContext, wrapper, Locale.US, inputValues[i]);
482     }
483     mock.verify();
484   }
485 
486   public void testSettingFractDigitsAndSettingMinDigitsAreHononured()
487   {
488     Number[] inputValues = {new Long(1234), new Double(1234.5678), new Double(1234), new Double(10.00)};
489     String[] expectedValues = {"1,234", "34.57", "1,234", "10.00"};
490 
491     int[] maxFractDigits = {0, 2, 2, 2};
492     int[] maxIntDigits   = {4, 2, 4, 3};
493     int[] minIntDigits   = {4, 1, 2, 1};
494     int[] minFractDigits = {0, 2, 0, 2};
495 
496     NumberConverter converter   = getNumberConverter();
497     Mock mock = mock(UIComponent.class);
498     UIComponent component = (UIComponent) mock.proxy();
499     //we do not care about getValueExpression() being called or not
500     mock.stubs().method("getValueExpression");
501 
502     setFacesContext(facesContext);
503     try
504     {
505       converter.setLocale(Locale.US);
506       for (int i = 0; i < maxFractDigits.length; i++)
507       {
508         converter.setMaxFractionDigits(maxFractDigits[i]);
509         converter.setMaxIntegerDigits(maxIntDigits[i]);
510         converter.setMinFractionDigits(minFractDigits[i]);
511         converter.setMinIntegerDigits(minIntDigits[i]);
512         
513         String out = converter.getAsString(facesContext, component, inputValues[i]);
514         assertEquals(expectedValues[i], out);   
515       }
516     }
517     finally
518     {
519       setFacesContext(null);
520     }
521     mock.verify();
522   }
523 
524   protected abstract NumberConverter getNumberConverter();
525 
526   protected abstract void doTestStrictNess(
527     MockFacesContext context,
528     MockUIComponentWrapper wrapper,
529     Locale locale,
530     String inputValue);
531 
532   private static final String[] _CURRENCY_CODES = {"USD", "DEM" };
533 
534   private static final String[] _CURRENCY_SYMBOLS = {"*", "!"};
535 
536   private static final Locale[] _LOCALES = {Locale.US, Locale.GERMAN};
537 
538   private static final int[] _MAX_FRACTION_DIGITS = {2, 3};
539 
540   private static final int[] _MAX_INT_DIGITS = {5, 6};
541 
542   private static final int[] _MIN_FRACT_DIGITS = {2, 3};
543 
544   private static final int[] _MIN_INT_DIGITS = {2, 3};
545 
546   private static final String[] _PATTTERNS = {"##,##", null};
547 
548   private static final String[] _TYPES = {"currency","percent"};
549 
550   // -= Simon Lessard =-
551   // TODO: Never read locally as of 2006-08-09. Remove whenever possible
552   //       or implements a grouping test using this constant.
553   //private static final boolean[] _GROUPING = {true, false};
554 
555   private static final boolean[] _INTEGER_ONLY = {true, false};
556 
557   private static final boolean[] _TRANSIENT = {true, false};
558 
559 }
560 // DONOT DELETE LET THESE STAY HERE.
561 // CurrencyCode
562 // CurrencySymbol
563 // Locale
564 // MaxFractionDigits
565 // MaxIntegerDigits
566 // MinFractionDigits
567 // MinIntegerDigits
568 // Pattern
569 // Type
570 // GroupingUsed
571 // IntegerOnly
572 
573 //Currency Code | Country Currency
574 //USD - United States Dollar
575 //
576 //ITL - Italian Lira
577 //
578 //DEM - German Mark
579 //
580 //HKG - Hong Kong Dollar
581 //
582 //MXN - Mexican Peso
583 //
584 //EUR - Euro
585 
586 // CurrencyCode        tested
587 // CurrencySymbol      tested
588 // Locale              tested  to pick up from viewRoot
589 
590 
591 // MaxFractionDigits      only while formatting
592 // MaxIntegerDigits       only while formatting
593 // MinFractionDigits      only while formatting
594 // MinIntegerDigits       only while formatting
595 
596 // Pattern             tested
597 // Type                tested
598 // GroupingUsed        tested
599 // IntegerOnly         tested   // only while parsing