1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.log4j.pattern;
19  
20  import junit.framework.Test;
21  import junit.framework.TestCase;
22  import junit.framework.TestSuite;
23  
24  import org.apache.log4j.pattern.CachedDateFormat;
25  
26  import java.text.DateFormat;
27  import java.util.TimeZone;
28  import java.util.Date;
29  import java.text.SimpleDateFormat;
30  import java.util.Locale;
31  import java.util.Calendar;
32  
33  /**
34     Unit test {@link AbsoluteTimeDateFormat}.
35     @author Curt Arnold
36     */
37  public final class CachedDateFormatTest
38      extends TestCase {
39  
40    /**
41     * Test constructor
42     * @param name String test name
43     */
44    public CachedDateFormatTest(String name) {
45      super(name);
46    }
47    
48    private static DateFormat createAbsoluteTimeDateFormat(TimeZone timeZone) {
49        DateFormat df = new SimpleDateFormat("HH:mm:ss,SSS");
50        df.setTimeZone(timeZone);
51        return df;
52    }
53  
54  
55    /**
56     * Timezone representing GMT.
57     */
58    private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
59  
60    /**
61     * Timezone for Chicago, Ill. USA.
62     */
63    private static final TimeZone CHICAGO = TimeZone.getTimeZone(
64        "America/Chicago");
65  
66    /**
67     * Test multiple calls in close intervals.
68     */
69    public void test1() {
70      //   subsequent calls within one minute
71      //     are optimized to reuse previous formatted value
72      //     make a couple of nearly spaced calls
73      DateFormat gmtFormat = new CachedDateFormat(createAbsoluteTimeDateFormat(GMT), 1000);
74      long ticks = 12601L * 86400000L;
75      Date jul1 = new Date(ticks);
76      assertEquals("00:00:00,000", gmtFormat.format(jul1));
77      Date plus8ms = new Date(ticks + 8);
78      assertEquals("00:00:00,008", gmtFormat.format(plus8ms));
79      Date plus17ms = new Date(ticks + 17);
80      assertEquals("00:00:00,017", gmtFormat.format(plus17ms));
81      Date plus237ms = new Date(ticks + 237);
82      assertEquals("00:00:00,237", gmtFormat.format(plus237ms));
83      Date plus1415ms = new Date(ticks + 1415);
84      assertEquals("00:00:01,415", gmtFormat.format(plus1415ms));
85    }
86  
87    /**
88     *  Check for interaction between caches.
89     */
90    public void test2() {
91        Date jul2 = new Date(12602L * 86400000L);
92        DateFormat gmtFormat = new CachedDateFormat(createAbsoluteTimeDateFormat(GMT), 1000);
93        DateFormat chicagoFormat = new CachedDateFormat(createAbsoluteTimeDateFormat(CHICAGO), 1000);
94        assertEquals("00:00:00,000", gmtFormat.format(jul2));
95        assertEquals("19:00:00,000", chicagoFormat.format(jul2));
96        assertEquals("00:00:00,000", gmtFormat.format(jul2));
97    }
98  
99    /**
100    * Test multiple calls in close intervals prior to 1 Jan 1970.
101    */
102   public void test3() {
103     //   subsequent calls within one minute
104     //     are optimized to reuse previous formatted value
105     //     make a couple of nearly spaced calls
106     DateFormat gmtFormat = new CachedDateFormat(
107        createAbsoluteTimeDateFormat(GMT), 1000);
108     //
109     //  if the first call was exactly on an integral
110     //     second, it would not test the round toward zero compensation
111     long ticks = -7L * 86400000L;
112     Date jul1 = new Date(ticks + 8);
113     assertEquals("00:00:00,008", gmtFormat.format(jul1));
114     Date plus8ms = new Date(ticks + 16);
115     assertEquals("00:00:00,016", gmtFormat.format(plus8ms));
116     Date plus17ms = new Date(ticks + 23);
117     assertEquals("00:00:00,023", gmtFormat.format(plus17ms));
118     Date plus237ms = new Date(ticks + 245);
119     assertEquals("00:00:00,245", gmtFormat.format(plus237ms));
120     Date plus1415ms = new Date(ticks + 1423);
121     assertEquals("00:00:01,423", gmtFormat.format(plus1415ms));
122   }
123 
124   public void test4() {
125     //  subsequent calls within one minute are optimized to reuse previous 
126     //  formatted value. make a couple of nearly spaced calls
127     // (Note: 'Z' is JDK 1.4, using 'z' instead.)
128     SimpleDateFormat baseFormat =
129          new SimpleDateFormat("EEE, MMM dd, HH:mm:ss.SSS z", Locale.ENGLISH);
130     DateFormat cachedFormat = new CachedDateFormat(baseFormat, 1000);
131     //
132     //   use a date in 2000 to attempt to confuse the millisecond locator
133     long ticks = 11141L * 86400000L;
134     Date jul1 = new Date(ticks);
135     assertEquals(baseFormat.format(jul1), cachedFormat.format(jul1));
136     Date plus8ms = new Date(ticks + 8);
137     baseFormat.format(plus8ms);
138     cachedFormat.format(plus8ms);
139     assertEquals(baseFormat.format(plus8ms), cachedFormat.format(plus8ms));
140     Date plus17ms = new Date(ticks + 17);
141     assertEquals(baseFormat.format(plus17ms), cachedFormat.format(plus17ms));
142     Date plus237ms = new Date(ticks + 237);
143     assertEquals(baseFormat.format(plus237ms), cachedFormat.format(plus237ms));
144     Date plus1415ms = new Date(ticks + 1415);
145     assertEquals(baseFormat.format(plus1415ms), cachedFormat.format(plus1415ms));
146   }
147 
148   public void test5() {
149     //   subsequent calls within one minute
150     //     are optimized to reuse previous formatted value
151     //     make a couple of nearly spaced calls
152     // (Note: 'Z' is JDK 1.4, using 'z' instead.)
153     Locale thai = new Locale("th", "TH");
154     SimpleDateFormat baseFormat =
155          new SimpleDateFormat("EEE, MMM dd, HH:mm:ss.SSS z", thai);
156     DateFormat cachedFormat = new CachedDateFormat(baseFormat, 1000);
157     //
158     // use a date in the year 2000 CE to attempt to confuse the millisecond locator
159     long ticks = 11141L * 86400000L;
160    
161     String sx;
162     Date jul1 = new Date(ticks);
163     sx = cachedFormat.format(jul1);
164     System.out.println(baseFormat.format(jul1));
165     System.out.println(sx);
166     assertEquals(baseFormat.format(jul1), sx);
167     
168     sx = cachedFormat.format(jul1);
169     System.out.println(baseFormat.format(jul1));
170     System.out.println(sx);
171     assertEquals(baseFormat.format(jul1), sx);
172     
173     
174     Date plus8ms = new Date(ticks + 8);
175     sx = cachedFormat.format(plus8ms);
176     System.out.println(baseFormat.format(plus8ms));
177     System.out.println(sx);
178     
179     assertEquals(baseFormat.format(plus8ms), sx);
180     
181     Date plus17ms = new Date(ticks + 17);
182     assertEquals(baseFormat.format(plus17ms), cachedFormat.format(plus17ms));
183     
184     Date plus237ms = new Date(ticks + 237);
185     assertEquals(baseFormat.format(plus237ms), cachedFormat.format(plus237ms));
186     
187     Date plus1415ms = new Date(ticks + 1415);
188     assertEquals(baseFormat.format(plus1415ms), cachedFormat.format(plus1415ms));
189   }
190 
191   /**
192    * Checks that getNumberFormat does not return null.
193    */
194   public void test6() {
195     assertNotNull(new CachedDateFormat(new SimpleDateFormat(), 1000).getNumberFormat());
196   }
197 
198   /**
199    * Set time zone on cached and check that it is effective.
200    */
201   public void test8() {
202     DateFormat baseFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
203     baseFormat.setTimeZone(GMT);
204     DateFormat cachedFormat = new CachedDateFormat(baseFormat, 1000);
205     Date jul4 = new Date(12603L * 86400000L);
206     assertEquals("2004-07-04 00:00:00,000", cachedFormat.format(jul4));
207     cachedFormat.setTimeZone(TimeZone.getTimeZone("GMT-6"));
208     assertEquals("2004-07-03 18:00:00,000", cachedFormat.format(jul4));
209   }
210 
211 
212   /**
213    * Test of caching when less than three millisecond digits are specified.
214    */
215   public void test9() {
216     // (Note: 'Z' is JDK 1.4, using 'z' instead.)
217     DateFormat baseFormat = new SimpleDateFormat("yyyy-MMMM-dd HH:mm:ss,SS z", Locale.US);
218     DateFormat cachedFormat = new CachedDateFormat(baseFormat, 1000);
219     TimeZone cet = TimeZone.getTimeZone("GMT+1");
220     cachedFormat.setTimeZone(cet);
221     
222     Calendar c = Calendar.getInstance();
223     c.set(2004, Calendar.DECEMBER, 12, 20, 0);
224     c.set(Calendar.SECOND, 37);
225     c.set(Calendar.MILLISECOND, 23);
226     c.setTimeZone(cet);
227 
228     String expected = baseFormat.format(c.getTime());
229     String s = cachedFormat.format(c.getTime());
230     assertEquals(expected, s);
231 
232     c.set(2005, Calendar.JANUARY, 1, 0, 0);
233     c.set(Calendar.SECOND, 13);
234     c.set(Calendar.MILLISECOND, 905);
235 
236     expected = baseFormat.format(c.getTime());
237     s = cachedFormat.format(c.getTime());
238     assertEquals(expected, s);
239   }
240   
241 
242   /**
243    * Test when millisecond position moves but length remains constant.
244    */
245   public void test10() {
246     DateFormat baseFormat = new SimpleDateFormat("MMMM SSS EEEEEE", Locale.US);
247     DateFormat cachedFormat = new CachedDateFormat(baseFormat, 1000);
248     TimeZone cet = TimeZone.getTimeZone("GMT+1");
249     cachedFormat.setTimeZone(cet);
250     
251     Calendar c = Calendar.getInstance();
252     c.set(2004, Calendar.OCTOBER, 5, 20, 0);
253     c.set(Calendar.SECOND, 37);
254     c.set(Calendar.MILLISECOND, 23);
255     c.setTimeZone(cet);
256 
257     String expected = baseFormat.format(c.getTime());
258     String s = cachedFormat.format(c.getTime());
259     assertEquals(expected, s);
260 
261     c.set(2004, Calendar.NOVEMBER, 1, 0, 0);
262     c.set(Calendar.MILLISECOND, 23);
263     expected = baseFormat.format(c.getTime());
264     s = cachedFormat.format(c.getTime());
265     assertEquals(expected, s);
266 
267 
268     c.set(Calendar.MILLISECOND, 984);
269     expected = baseFormat.format(c.getTime());
270     s = cachedFormat.format(c.getTime());
271     assertEquals(expected, s);
272   }
273 
274   /**
275    * Test that tests if caching is skipped if only "SS"
276    *     is specified.
277    */
278   public void test11() {
279      //
280      //   Earlier versions could be tricked by "SS0" patterns.
281      //
282      String badPattern = "ss,SS0";
283      SimpleDateFormat simpleFormat = new SimpleDateFormat(badPattern);
284      SimpleDateFormat baseFormat = new SimpleDateFormat(badPattern);
285      DateFormat gmtFormat = new CachedDateFormat(simpleFormat, 1000);
286      gmtFormat.setTimeZone(GMT);
287      baseFormat.setTimeZone(GMT);
288 
289      //
290      // The first request has to 100 ms after an ordinal second
291      //    to push the literal zero out of the pattern check
292      long ticks = 11142L * 86400000L;
293      Date jul2 = new Date(ticks + 120);
294      String expected = baseFormat.format(jul2);
295      assertEquals(expected, gmtFormat.format(jul2));
296      jul2.setTime(ticks + 87);
297      
298 
299      //
300      //   Cache gives 00,087
301      expected = baseFormat.format(jul2);
302      assertEquals(expected, gmtFormat.format(jul2));
303 
304   }
305 
306   /**
307    * Check pattern location for ISO8601
308    */
309   public void test12() {
310      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
311      long ticks = 11142L * 86400000L;
312      String formatted = df.format(new Date(ticks));
313      int millisecondStart = CachedDateFormat.findMillisecondStart(ticks, formatted, df);
314      assertEquals(20, millisecondStart);     
315   }
316 
317   /**
318    * Check pattern location for DATE
319    */
320   public void test13() {
321      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
322      long ticks = 11142L * 86400000L;
323      String formatted = df.format(new Date(ticks));
324      int millisecondStart = CachedDateFormat.findMillisecondStart(ticks, formatted, df);
325      assertEquals(CachedDateFormat.NO_MILLISECONDS, millisecondStart);     
326   }
327 
328   /**
329    * Check pattern location for ABSOLUTE
330    */
331   public void test14() {
332      SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss,SSS");
333      long ticks = 11142L * 86400000L;
334      String formatted = df.format(new Date(ticks));
335      int millisecondStart = CachedDateFormat.findMillisecondStart(ticks, formatted, df);
336      assertEquals(9, millisecondStart);     
337   }
338 
339   /**
340    * Check pattern location for single S
341    */
342   public void test15() {
343      SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss,S");
344      long ticks = 11142L * 86400000L;
345      String formatted = df.format(new Date(ticks));
346      int millisecondStart = CachedDateFormat.findMillisecondStart(ticks, formatted, df);
347      assertEquals(CachedDateFormat.UNRECOGNIZED_MILLISECONDS, millisecondStart);     
348   }
349 
350   /**
351    * Check pattern location for single SS
352    */
353   public void test16() {
354      SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss,SS");
355      long ticks = 11142L * 86400000L;
356      String formatted = df.format(new Date(ticks));
357      int millisecondStart = CachedDateFormat.findMillisecondStart(ticks, formatted, df);
358      assertEquals(CachedDateFormat.UNRECOGNIZED_MILLISECONDS, millisecondStart);     
359   }
360 
361 
362   /**
363    * Check caching when multiple SSS appear in pattern
364    */
365   public void test17() {
366       Date jul2 = new Date(12602L * 86400000L);
367       String badPattern = "HH:mm:ss,SSS HH:mm:ss,SSS";
368       SimpleDateFormat simpleFormat = new SimpleDateFormat(badPattern);
369       simpleFormat.setTimeZone(GMT);
370       DateFormat cachedFormat = new CachedDateFormat(simpleFormat, 1000);
371       String s = cachedFormat.format(jul2);
372       assertEquals("00:00:00,000 00:00:00,000", s);
373       jul2.setTime(jul2.getTime() + 120);
374       assertEquals("00:00:00,120 00:00:00,120", simpleFormat.format(jul2));
375       s = cachedFormat.format(jul2);
376       //
377       //  TODO: why is this returning ,120 ... , 120
378       //
379       //assertEquals("00:00:00,120 00:00:00,000", s) ;
380       
381       int maxValid = CachedDateFormat.getMaximumCacheValidity(badPattern);
382       assertEquals(1, maxValid);
383   }
384 
385   
386   public static Test xsuite() {
387     TestSuite suite = new TestSuite();
388     suite.addTest(new CachedDateFormatTest("test5"));
389     //suite.addTest(new CachedDateFormatTest("testS2"));
390     return suite;
391   }
392 
393 }