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.Calendar;
22  import java.util.Date;
23  import java.util.GregorianCalendar;
24  import java.util.Locale;
25  import java.util.TimeZone;
26  
27  import javax.faces.component.UIComponent;
28  import javax.faces.convert.Converter;
29  import javax.faces.convert.ConverterException;
30  
31  import junit.framework.Test;
32  import junit.framework.TestSuite;
33  
34  import org.apache.myfaces.trinidad.context.MockRequestContext;
35  import org.apache.myfaces.trinidad.convert.DateTimeConverter;
36  import org.apache.myfaces.trinidadbuild.test.MockUIComponentWrapper;
37  import org.apache.shale.test.mock.MockFacesContext;
38  import org.jmock.Mock;
39  
40  public class TrinidadDateTimeConverterTest extends DateTimeConverterTestCase
41  {
42    public TrinidadDateTimeConverterTest(String name)
43    {
44      super(name);
45    }
46    
47    @Override
48    protected void setUp() throws Exception
49    {
50      super.setUp();
51      _mafct = new MockRequestContext();
52      _mafct.setTwoDigitYearStart(1950);
53      _mafct.setTimeZone(DEFAULT_TIME_ZONE);
54    }
55  
56    @Override
57    protected void tearDown() throws Exception
58    {
59      super.tearDown();
60      _mafct.release();
61      _mafct = null;
62    }
63    
64    public static Test suite()
65    {
66      return new TestSuite(TrinidadDateTimeConverterTest.class);
67    }
68  
69    public void testConveniencePatterns()
70    {
71      DateTimeConverter dtConv   = new DateTimeConverter();
72      dtConv.setLocale(Locale.US);
73  
74      //this is what SimpleInputDateRenderer does
75      if(dtConv.getTimeZone() == null)
76      {
77        TimeZone tz = null;
78        tz = _mafct.getTimeZone();
79        if(tz == null)
80          tz = TimeZone.getDefault();
81        dtConv.setTimeZone(tz);
82      }
83  
84      Mock mock = buildMockUIComponent();
85      UIComponent component = (UIComponent) mock.proxy();
86      String[] inputValue = {"15/2/2002", "January 4, 2004", "4-JAnuARY-2004", "JANUARY/4/2007", "Jan 4, 2004",
87          "01/4/2004", "01-4-2004", "01.4.2004", "1/4/2004", "1-4-2004", "1.4.2004", "Jan/4/2004", "Jan-4-2004",
88          "Jan.4.2004", "04-jan-2004", "4-jan-04", "4-jan-2004", "04-jAn-04", "04-JAN-04", "04-JAN-2004",
89          "4-JAN-04", "4-JAN-2004", "January 4, 2004", "Jan 4, 2004"};
90  
91      for(int i = 0; i < inputValue.length; i++)
92      {
93        dtConv.getAsObject(facesContext, component, inputValue[i]);
94      }
95    }
96  
97    public void testFormatedPatterns()
98    {
99      DateTimeConverter dtConv   = new DateTimeConverter();
100     dtConv.setLocale(Locale.US);
101 
102     //this is what SimpleInputDateRenderer does
103     if(dtConv.getTimeZone() == null)
104     {
105       TimeZone tz = null;
106       tz = _mafct.getTimeZone();
107       if(tz == null)
108         tz = TimeZone.getDefault();
109       dtConv.setTimeZone(tz);
110     }
111 
112     Mock mock = buildMockUIComponent();
113     UIComponent component = (UIComponent) mock.proxy();
114     String[] inputValue = {"15/2/2002", "January 4, 2004", "4-JAnuARY-2004", "JANUARY/4/2007"};
115     String[] formatedStrings = {"2/15/2002", "1/4/2004", "1/4/2004", "1/4/2007"};
116 
117     Date convertedDate = null;
118     String returnedString = null;
119     for(int i = 0; i < inputValue.length; i++)
120     {
121       convertedDate = (Date) dtConv.getAsObject(facesContext, component, inputValue[i]);
122       returnedString = dtConv.getAsString(facesContext, component, convertedDate);
123       assertEquals(returnedString, formatedStrings[i]);
124     }
125   }
126 
127   /**
128    * @todo move this to the parent class once JSF fixes the bug
129    */
130   public void testEarlyExits()
131   {
132     checkNullComponent();
133     checkNullContext();
134   }
135 
136   public void testGermanDate()
137   {
138     DateTimeConverter dtConv   = new DateTimeConverter();
139     Mock mock = buildMockUIComponent();
140     UIComponent component = (UIComponent) mock.proxy();
141     String inputValue          = "30.06.09 12:11 Uhr ";
142 
143     dtConv.setType("both");
144     dtConv.setTimeStyle("full");
145     dtConv.setLocale(Locale.GERMAN);
146     dtConv.setTimeZone(TimeZone.getTimeZone ("America/New_York"));
147     dtConv.setPattern("dd.MM.yy HH:mm' Uhr '");
148 
149     Date dt = (Date) dtConv.getAsObject(facesContext, component, inputValue);
150     assertNotNull(dt);
151     mock.verify();
152   }
153 
154   public void testShortishForDatePatern()
155   {
156     GregorianCalendar gcal = new GregorianCalendar();
157     gcal.set(2999,Calendar.JUNE,4,0,0,0);
158 
159     gcal.setTimeZone(DEFAULT_TIME_ZONE);
160     // Make use of this date for testing.
161     Date date = gcal.getTime();
162 
163     DateTimeConverter dtConv   = new DateTimeConverter();
164     Mock mock = buildMockUIComponent();
165     UIComponent component = (UIComponent) mock.proxy();
166     String inputValue          = "6/4/2999";
167 
168     dtConv.setDateStyle("shortish");
169     dtConv.setLocale(Locale.ENGLISH);
170 
171     Date dt = (Date) dtConv.getAsObject(facesContext, component, inputValue);
172     assertEquals(true, isEqual(date, dt));
173 
174     String exptectedStr = dtConv.getAsString(facesContext, component, dt);
175     assertEquals(inputValue, exptectedStr);
176     mock.verify();
177   }
178 
179   public void testShortishDateStyle()
180   {
181     doTestStyleValidity(_DATE_STYLE, new String[]{"shortish"});
182   }
183 
184   public void testSecondaryPattern()
185   {
186     // Get as object should work fine - while getAsString is expected to fail
187     GregorianCalendar gcal = new GregorianCalendar();
188     gcal.set(1600,Calendar.JUNE,4,0,0,0);
189 
190     gcal.setTimeZone(DEFAULT_TIME_ZONE);
191     // Make use of this date for testing.
192     Date date = gcal.getTime();
193 
194     DateTimeConverter dtConv   = new DateTimeConverter();
195     Mock mock = buildMockUIComponent();
196     UIComponent component = (UIComponent) mock.proxy();
197     String inputValue          = "6/4/1600";
198     String secondaryPattern    = "MM/d/yyyy";
199 
200     dtConv.setLocale(Locale.US);
201     dtConv.setDateStyle("Let us unset it ");
202     dtConv.setType("Let us un set it");
203     dtConv.setSecondaryPattern(secondaryPattern);
204     // This should work fine
205     Date dt = (Date) dtConv.getAsObject(facesContext, component, inputValue);
206     assertEquals(true, isEqual(date, dt));
207 
208     try
209     {
210       dtConv.getAsString(facesContext, component, dt);
211       fail("Use of secondary pattern in the above fashion is expected to fail here");
212     }
213     catch (RuntimeException ce)
214     {
215       // Just proceed . This is the expected state
216     }
217 
218     dtConv.setDateStyle("shortish");
219     dtConv.setType("date");
220 
221     // now we set date and type so this is expected to work fine.
222 
223     String expectedOut = dtConv.getAsString(facesContext, component, date);
224     assertEquals(inputValue, expectedOut);
225 
226     mock.verify();
227   }
228 
229   public void testLeniencyOnPrimaryPattern()
230   {
231     String primaryPattern = "MMM/d/yyyy";
232     String secondaryPattern = null;
233     dotestLeniencyOnPattern(primaryPattern, secondaryPattern);
234   }
235 
236   public void testLeniencyOnSecondaryPattern()
237   {
238     String primaryPattern = null;
239     String secondaryPattern = "MMM/d/yyyy";
240     dotestLeniencyOnPattern(primaryPattern, secondaryPattern);
241   }
242 
243   protected void dotestLeniencyOnPattern(
244     String primaryPattern,
245     String secondaryPatttern
246     )
247   {
248     // inputs such as 6/7/2004 is also valid. Avoiding it since - equality
249     // of the output is also compared.
250 
251     // Each of these inputs ends up causing the MessageFactory to grab the
252     // label from the component a different number of times, so the number of
253     // iterations to set the component up for is difficult to figure. The
254     // numbers after the input string are the number of iterations of
255     // getAttribute that we need to set up for.
256     String[] validInputs =
257       {
258         "Jun/4/2004" /* 0 */, "Jun-4-2004" /* 10 */, "Jun.4.2004" /* 8 */,
259         "06/4/2004"  /* 4 */, "06-04-2004" /* 12 */, "06.04.2004" /* 2 */,
260         "6/4/2004"   /* 4 */, "6-4-2004"   /* 12 */, "6.4.2004"   /* 2 */
261       };
262 
263     int iterations = (0 + 10 + 8 + 4 + 12 + 2 + 4 + 12 + 2);
264     GregorianCalendar cal = new GregorianCalendar(2004, Calendar.JUNE, 4);
265     cal.setTimeZone(DEFAULT_TIME_ZONE);
266     Date dt = cal.getTime();
267     Mock mock = buildMockUIComponent(iterations);
268     UIComponent component = (UIComponent) mock.proxy();
269     
270     for (int i = 0; i < validInputs.length; i++)
271     {
272       DateTimeConverter
273         dtConv = (DateTimeConverter) getDateTimeConverter();
274       dtConv.setLocale(Locale.ENGLISH);
275       dtConv.setPattern(primaryPattern);
276       dtConv.setSecondaryPattern(secondaryPatttern);
277       dtConv.setTimeZone(DEFAULT_TIME_ZONE);
278       dtConv.setType("INVALID"); // make this type invalid
279 
280       Date convDate = (Date) dtConv.getAsObject(facesContext, component,
281                                                 validInputs[i]);
282       assertEquals(convDate, dt);
283       mock.verify();
284     }
285   }
286 
287   public void testCompareDateTimeConverter()
288   {
289     Object[][] data = _getDataForPatterns();
290 
291     for (int i = 0; i < data.length ; i++)
292     {
293       DateTimeConverter dtConv = new DateTimeConverter();
294       dtConv.setPattern((String)data[i][0]);
295       dtConv.setLocale((Locale)data[i][2]);
296       dtConv.setTimeZone((TimeZone)data[i][3]);
297       String inputValue = (String)data[i][1];
298 
299       javax.faces.convert.DateTimeConverter fdtConv
300         = new javax.faces.convert.DateTimeConverter();
301       fdtConv.setPattern((String)data[i][0]);
302       fdtConv.setLocale((Locale)data[i][2]);
303       fdtConv.setTimeZone((TimeZone)data[i][3]);
304 
305       Mock mock = buildMockUIComponent();
306       UIComponent component = (UIComponent) mock.proxy();
307       Date dtConvDate  = (Date)dtConv.getAsObject(facesContext, component, inputValue);
308       Date fdtConvDate = (Date)fdtConv.getAsObject(facesContext, component, inputValue);
309       //      assertEquals(dtConvDate, fdtConvDate);
310 
311       dtConv.getAsString(facesContext, component, dtConvDate);
312       fdtConv.getAsString(facesContext, component, fdtConvDate);
313       //      assertEquals(dtConvPattern, fdtConvPattern);
314     }
315   }
316 
317   @Override
318   protected javax.faces.convert.DateTimeConverter getDateTimeConverter()
319   {
320     return new DateTimeConverter();
321   }
322 
323   @Override
324   protected void setSecondaryPattern(
325     javax.faces.convert.DateTimeConverter converter,
326     String secondaryPattern
327     )
328   {
329     ((DateTimeConverter)converter).setSecondaryPattern(secondaryPattern);
330   }
331 
332   @Override
333   protected void doTestStateHolderSaveRestore(
334     Converter conv1,
335     Converter conv2,
336     MockFacesContext context,
337     MockUIComponentWrapper wrapper
338     )
339   {
340     super.doTestStateHolderSaveRestore(conv1, conv2, context, wrapper);
341   }
342 
343   public void testCustomMessageIsSet()
344   {
345     //default is shortish - M/d/yyyy
346     //default time is short hh:m A.M/P.M
347     //default both
348     //let us choose pattern as M/d/yyyy
349     String[] failingValues = {"15/15/2002", "02;30 A.M,", "15/15/2002 22:22 A*M.", "M/d/yyyy"};
350     String[] types         = {"date",   "time",  "both", "pattern"};
351     String[] customMessage = {"date",   "time",  "both", "pattern"};
352 
353     for (int i = 0; i < failingValues.length ; i++)
354     {
355       Mock mock = buildMockUIComponent(3 * 4);
356       UIComponent component = (UIComponent) mock.proxy();
357 
358       org.apache.myfaces.trinidad.convert.DateTimeConverter converter =
359         new org.apache.myfaces.trinidad.convert.DateTimeConverter();
360 
361       for (int j = 0; j < 3; j++)
362       {
363         for (int k = 0; k < 4; k++)
364           facesContext.getViewRoot().setLocale(Locale.US);
365       }
366 
367       try
368       {
369         // Trinidad Converter is not lenient.
370         converter.setMessageDetailConvertDate(customMessage[0]);
371         converter.setMessageDetailConvertTime(customMessage[1]);
372         converter.setMessageDetailConvertBoth(customMessage[2]);
373         // pattern and date type is driven using the same message.
374 
375 
376         if ("pattern".equals(types[i]))
377         {
378           converter.setPattern("M/d/yyyy");
379           // There is no specific messaging scheme for pattern. So use the
380           // dateMessageDetail itself for this.
381           converter.setMessageDetailConvertDate(customMessage[3]);
382         }
383         else
384         {
385           converter.setType(types[i]);
386         }
387 
388         converter.getAsObject(facesContext, component, failingValues[i]);
389         fail("Expected converter exception");
390       }
391       catch (ConverterException ce)
392       {
393         // We expected a exception to occur
394         String msg = ce.getFacesMessage().getDetail();
395         assertEquals(msg, customMessage[i]);
396       }
397     }
398   }
399 
400   private Object[][] _getDataForPatterns()
401   {
402     // pattern, inputvalue,locale,timezone
403     Object[][] data =
404     {
405       {"yyyy.MM.dd G 'at' HH:mm:ss z", "2001.07.04 AD at 12:08:56 PDT", Locale.US, null },
406 
407       {"EEE, MMM d, ''yy","Wed, Jul 4, '01", Locale.ENGLISH, getTzone("GMT")},
408 
409       {"h:mm a","12:08 PM", Locale.GERMAN, getTzone("GMT+1")},
410 
411       {"hh 'o''clock' a, zzzz","12 o'clock PM, Pacific Standard Time", Locale.CANADA, getTzone("GMT-8")},
412 
413       {"K:mm a, z","0:08 PM, PST", Locale.US, getTzone("PST")},
414 
415       {"yyyyy.MMMMM.dd GGG hh:mm aaa","02001.July.04 AD 12:08 PM", Locale.US, null},
416       {"EEE, d MMM yyyy HH:mm:ss Z","Wed, 4 Jul 2001 12:08:56 GMT",Locale.US, getTzone("GMT")},
417       {"yyMMddHHmmss", "010704120856", Locale.ENGLISH, null, null},
418 
419     };
420     return data;
421   }
422 
423   private MockRequestContext _mafct;
424 
425   private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getDefault();
426 }