OSDN Git Service

split Cookie-Date parsing
authorOlyutorskii <olyutorskii@users.osdn.me>
Fri, 10 Aug 2012 13:10:18 +0000 (22:10 +0900)
committerOlyutorskii <olyutorskii@users.osdn.me>
Fri, 10 Aug 2012 13:10:18 +0000 (22:10 +0900)
* * *
Cookie-Date parsing test
* * *
新型Cookieパーサへ移行
* * *
Cookie内のDateの保持を廃止
* * *
Cookie仕様の定数化
* * *
プラグイン更新
* * *
DateFormatの隠蔽
* * *
メソッド名変更
* * *
コメント追記
* * *
RFC6265仕様に近づける
* * *
ソフトウェアメトリクス改善

pom.xml
src/main/java/jp/sfjp/jindolf/net/AccountCookie.java
src/main/java/jp/sfjp/jindolf/net/CookieDateParser.java [new file with mode: 0644]
src/test/java/jp/sfjp/jindolf/net/AccountCookieTest.java [new file with mode: 0644]
src/test/java/jp/sfjp/jindolf/net/CookieDateParserTest.java [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index f5f0b4d..c4b1e5f 100644 (file)
--- a/pom.xml
+++ b/pom.xml
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-enforcer-plugin</artifactId>
-                <version>1.1</version>
+                <version>1.1.1</version>
                 <configuration>
                     <rules>
                         <requireMavenVersion>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.12</version>
+                <version>2.12.1</version>
                 <configuration>
                     <skipTests>false</skipTests>
                     <enableAssertions>true</enableAssertions>
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>findbugs-maven-plugin</artifactId>
-                <version>2.3.3</version> <!-- 2.4.0 has BUG-->
+                <version>2.5.2</version>
                 <configuration>
                     <effort>Max</effort>
                     <threshold>Low</threshold>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-project-info-reports-plugin</artifactId>
-                <version>2.4</version>
+                <version>2.5</version>
                 <configuration>
                     <linkOnly>true</linkOnly>
                     <offline>true</offline>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-report-plugin</artifactId>
-                <version>2.12</version>
+                <version>2.12.1</version>
                 <configuration>
                     <showSuccess>false</showSuccess>
                 </configuration>
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>findbugs-maven-plugin</artifactId>
-                <version>2.3.3</version> <!-- 2.4.0 has BUG-->
+                <version>2.5.2</version>
                 <configuration>
-                    <skip>true</skip>
+                    <skip>false</skip>
                     <effort>Max</effort>
                     <threshold>Low</threshold>
                     <!-- excludeFilterFile/ -->
index c53817e..38699cf 100644 (file)
@@ -10,63 +10,28 @@ package jp.sfjp.jindolf.net;
 import java.net.HttpURLConnection;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.text.DateFormatSymbols;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-import java.util.TimeZone;
 
 /**
  * 人狼BBSアカウント管理用のCookie。
- * JRE1.6 HttpCookie の代用品。
+ * <p>JRE1.6 java.net.HttpCookie の代用品。
+ * <p>人狼BBSではCookieヘッダに"Set-Cookie"が用いられる。
+ * (Set-Cookie2ではない)
+ * <p>人狼BBSではCookieの寿命管理に"Expires"が用いられる。(Max-Ageではない)
+ * <p>人狼BBSではセッション管理のCookie名に"login"が用いられる。
+ * @see <a href="http://www.ietf.org/rfc/rfc6265.txt">RFC6265</a>
  */
 class AccountCookie{          // TODO JRE 1.6対応とともにHttpCookieへ移行予定
 
-    // 人狼BBSのCookie期限表記例: 「Thu, 26 Jun 2008 06:44:34 GMT」
-    private static final String DATE_FORM = "EEE, dd MMM yyyy HH:mm:ss z";
-    private static final SimpleDateFormat FORMAT;
-
-    static{
-        Calendar calendar = new GregorianCalendar();
-        TimeZone zoneGMT = TimeZone.getTimeZone("GMT");
-        DateFormatSymbols customSyms = new DateFormatSymbols();
-        String[] sweekdays = customSyms.getShortWeekdays();
-        sweekdays[Calendar.SUNDAY] = "Sun";
-        sweekdays[Calendar.MONDAY] = "Mon";
-        sweekdays[Calendar.TUESDAY] = "Tue";
-        sweekdays[Calendar.WEDNESDAY] = "Wed";
-        sweekdays[Calendar.THURSDAY] = "Thu";
-        sweekdays[Calendar.FRIDAY] = "Fri";
-        sweekdays[Calendar.SATURDAY] = "Sat";
-        customSyms.setShortWeekdays(sweekdays);
-        String[] months = customSyms.getShortMonths();
-        months[Calendar.JANUARY] = "Jan";
-        months[Calendar.FEBRUARY] = "Feb";
-        months[Calendar.MARCH] = "Mar";
-        months[Calendar.APRIL] = "Apr";
-        months[Calendar.MAY] = "May";
-        months[Calendar.JUNE] = "Jun";
-        months[Calendar.JULY] = "Jul";
-        months[Calendar.AUGUST] = "Aug";
-        months[Calendar.SEPTEMBER] = "Sep";
-        months[Calendar.OCTOBER] = "Oct";
-        months[Calendar.NOVEMBER] = "Nov";
-        months[Calendar.DECEMBER] = "Dec";
-        customSyms.setShortMonths(months);
-
-        FORMAT = new SimpleDateFormat(DATE_FORM, Locale.JAPAN);
-        FORMAT.setCalendar(calendar);
-        FORMAT.setTimeZone(zoneGMT);
-        FORMAT.setDateFormatSymbols(customSyms);
-        FORMAT.setLenient(true);
-    }
+    private static final String HEADER_COOKIE = "Set-Cookie";
+    private static final String SEPARATOR = ";";
+    private static final String COOKIE_PATH = "Path";
+    private static final String COOKIE_EXPIRES = "Expires";
+    private static final String BBS_IDENTITY = "login";
+
 
     private final String loginData;
     private final URI pathURI;
-    private final Date expireDate;
+    private final long expireDate;
 
     /**
      * 認証クッキーの生成。
@@ -76,11 +41,11 @@ class AccountCookie{          // TODO JRE 1.6対応とともにHttpCookieへ移
      * @throws java.lang.NullPointerException 引数がnull
      * @throws java.lang.IllegalArgumentException パスが変
      */
-    public AccountCookie(String loginData, String path, Date expireDate)
+    public AccountCookie(String loginData, String path, long expireDate)
             throws NullPointerException, IllegalArgumentException{
         super();
 
-        if(loginData == null || path == null || expireDate == null){
+        if(loginData == null || path == null){
             throw new NullPointerException();
         }
 
@@ -96,69 +61,108 @@ class AccountCookie{          // TODO JRE 1.6対応とともにHttpCookieへ移
     }
 
     /**
-     * Cookie期限が切れてないか判定する。
-     * @return 期限が切れていたらtrue
+     * 文字列両端に連続するWSP(空白もしくはタブ)を取り除く。
+     * @param txt テキスト
+     * @return 取り除いた結果。引数がnullならnull
      */
-    public boolean hasExpired(){
-        long nowMs = System.currentTimeMillis();
-        long expireMs = this.expireDate.getTime();
-        if(expireMs < nowMs) return true;
-        return false;
+    static String chopWsp(String txt){
+        if(txt == null) return null;
+
+        int startPt = -1;
+        int endPt   = -1;
+
+        int len = txt.length();
+        for(int idx = 0; idx < len; idx++){
+            char ch = txt.charAt(idx);
+            if(ch != '\u0020' &&  ch != '\t'){
+                if(startPt < 0) startPt = idx;
+                endPt = idx + 1;
+            }
+        }
+
+        if(startPt < 0) startPt = 0;
+        if(endPt   < 0) endPt   = 0;
+
+        String result = txt.substring(startPt, endPt);
+
+        return result;
     }
 
     /**
-     * Cookieパスを返す。
-     * @return Cookieパス
+     * Cookie属性を名前と値に分割する。
+     * '='が無い属性(例:Secure)は値がnullになり、=付き空文字列とは区別される。
+     * 余分なWSP空白はトリミングされる。
+     * @param pair '='を挟む名前と値のペア。
+     * @return [0]名前 [1]値 ※空文字列の名前およびnullな値がありうる。
      */
-    public URI getPathURI(){
-        return this.pathURI;
+    static String[] splitPair(String pair){
+        String[] result = new String[2];
+
+        String[] split = pair.split("=", 2);
+
+        if(split.length >= 1){
+            result[0] = chopWsp(split[0]);
+        }
+
+        if(split.length >= 2){
+            result[1] = chopWsp(split[1]);
+        }
+
+        return result;
     }
 
     /**
-     * 認証データを返す。
-     * @return 認証データ
+     * 人狼BBS用ログインデータを抽出する。
+     * Cookie名は"login"。
+     * @param nameValue '='で区切られたCookie name-value構造
+     * @return 人狼BBS用ログインデータ。見つからなければnull
      */
-    public String getLoginData(){
-        return this.loginData;
+    private static String parseLoginData(String nameValue){
+        String[] nvPair = splitPair(nameValue);
+        String name  = nvPair[0];
+        String value = nvPair[1];
+        if(name.length() <= 0) return null;  // 名前なし
+        if(value == null) return null;       // '=' なし
+
+        if( ! BBS_IDENTITY.equals(name) ) return null;
+
+        return value;
     }
 
     /**
      * 認証Cookieを抽出する。
-     * @param cookieSource HTTPヘッダ 「Cookie=」の値
+     * @param cookieSource HTTPヘッダ 「Set-Cookie」の値
      * @return 認証Cookie
      */
     public static AccountCookie createCookie(String cookieSource){
-        String[] cookieParts = cookieSource.split("; ");
-        if(cookieParts.length <= 0) return null;
+        String[] cookiePart = cookieSource.split(SEPARATOR);
 
-        String login = null;
+        String login = parseLoginData(cookiePart[0]);
         String path = null;
         String expires = null;
-        for(String part : cookieParts){
-            String[] nmval = part.split("=", 2);
-            if(nmval == null) continue;
-            if(nmval.length != 2) continue;
-            String name = nmval[0];
-            String value = nmval[1];
-
-            if(name.equals("login")){
-                login = value;
-            }else if(name.equals("path")){
-                path = value;
-            }else if(name.equals("expires")){
-                expires = value;
+
+        int partNo = cookiePart.length;
+        for(int idx = 0 + 1; idx < partNo; idx++){
+            String pair = cookiePart[idx];
+            String[] attr = splitPair(pair);
+            String attrName  = attr[0];
+            String attrValue = attr[1];
+
+            if(COOKIE_PATH.equalsIgnoreCase(attrName)){
+                path = attrValue;
+            }else if(COOKIE_EXPIRES.equalsIgnoreCase(attrName)){
+                expires = attrValue;
             }
         }
-        if(login == null || path == null || expires == null) return null;
 
-        Date date;
-        try{
-            date = FORMAT.parse(expires);
-        }catch(ParseException e){
-            return null;
-        }
+        if(login   == null) return null;
+        if(path    == null) return null;
+        if(expires == null) return null;
 
-        AccountCookie cookie = new AccountCookie(login, path, date);
+        long expTime = CookieDateParser.parseToEpoch(expires);
+        if(expTime < 0L) return null;
+
+        AccountCookie cookie = new AccountCookie(login, path, expTime);
 
         return cookie;
     }
@@ -169,19 +173,56 @@ class AccountCookie{          // TODO JRE 1.6対応とともにHttpCookieへ移
      * @return 認証Cookie
      */
     public static AccountCookie createCookie(HttpURLConnection connection){
-        String cookieHeader = connection.getHeaderField("Set-Cookie");
+        String cookieHeader = connection.getHeaderField(HEADER_COOKIE);
         if(cookieHeader == null) return null;
         AccountCookie cookie = createCookie(cookieHeader);
         return cookie;
     }
 
     /**
-     * 認証Cookieの文字列表記。
-     * @return String文字列
+     * 認証データを返す。
+     * 取り扱い注意!人狼BBSでは機密情報だよ!
+     * @return 認証データ
      */
-    @Override
-    public String toString(){
+    public String getLoginData(){
         return this.loginData;
     }
 
+    /**
+     * Cookieパスを返す。
+     * @return Cookieパス
+     */
+    public URI getPathURI(){
+        return this.pathURI;
+    }
+
+    /**
+     * Cookie期限をエポック時刻で返す。
+     * @return Cookieが期限切れを起こす日時。(msec)
+     */
+    public long getExpiredTime(){
+        return this.expireDate;
+    }
+
+    /**
+     * Cookie期限が切れてないか判定する。
+     * @param nowMs 比較時刻(msec)
+     * @return 期限が切れていたらtrue
+     */
+    public boolean hasExpired(long nowMs){
+        long expireMs = getExpiredTime();
+        if(expireMs < nowMs) return true;
+        return false;
+    }
+
+    /**
+     * 現時点でCookie期限が切れてないか判定する。
+     * @return 期限が切れていたらtrue
+     */
+    public boolean hasExpired(){
+        long nowMs = System.currentTimeMillis();
+        boolean result = hasExpired(nowMs);
+        return result;
+    }
+
 }
diff --git a/src/main/java/jp/sfjp/jindolf/net/CookieDateParser.java b/src/main/java/jp/sfjp/jindolf/net/CookieDateParser.java
new file mode 100644 (file)
index 0000000..765ab0e
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * parser for Cookie-Date
+ *
+ * License : The MIT License
+ * Copyright(c) 2012 olyutorskii
+ */
+
+package jp.sfjp.jindolf.net;
+
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * 人狼BBS用Cookie日付のパースを行う。
+ * <p>デフォルトのロケールやタイムゾーンに依存しないよう設計される。
+ * <p>人狼BBSのCookie期限表記はRFC2616で"rfc-1123-date"として定義される。
+ * <p>例: 「Thu, 26 Jun 2008 06:44:34 GMT」
+ * @see <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC2616</a>
+ */
+final class CookieDateParser{
+
+    private static final String DATE_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z";
+    private static final Locale LOCALE_ROOT = new Locale("__", "", "");
+    private static final SimpleDateFormat PARSER;
+
+    static{
+        TimeZone zoneGMT = TimeZone.getTimeZone("GMT");
+        Calendar gcal = new GregorianCalendar(zoneGMT, LOCALE_ROOT);
+        DateFormatSymbols customSyms = buildSymbols();
+
+        PARSER = new SimpleDateFormat(DATE_PATTERN, LOCALE_ROOT);
+        PARSER.setTimeZone(zoneGMT);
+        PARSER.setCalendar(gcal);
+        PARSER.setDateFormatSymbols(customSyms);
+        PARSER.setLenient(true);
+    }
+
+
+    /**
+     * 隠しコンストラクタ。
+     */
+    private CookieDateParser(){
+        assert false;
+    }
+
+
+    /**
+     * 日付表記要素を定義する。
+     * @return 日付表記要素
+     */
+    private static DateFormatSymbols buildSymbols(){
+        DateFormatSymbols customSyms = new DateFormatSymbols(LOCALE_ROOT);
+
+        String[] sweekdays = customSyms.getShortWeekdays();
+        String[] smonths   = customSyms.getShortMonths();
+
+        sweekdays[Calendar.SUNDAY   ] = "Sun";
+        sweekdays[Calendar.MONDAY   ] = "Mon";
+        sweekdays[Calendar.TUESDAY  ] = "Tue";
+        sweekdays[Calendar.WEDNESDAY] = "Wed";
+        sweekdays[Calendar.THURSDAY ] = "Thu";
+        sweekdays[Calendar.FRIDAY   ] = "Fri";
+        sweekdays[Calendar.SATURDAY ] = "Sat";
+
+        smonths[Calendar.JANUARY  ] = "Jan";
+        smonths[Calendar.FEBRUARY ] = "Feb";
+        smonths[Calendar.MARCH    ] = "Mar";
+        smonths[Calendar.APRIL    ] = "Apr";
+        smonths[Calendar.MAY      ] = "May";
+        smonths[Calendar.JUNE     ] = "Jun";
+        smonths[Calendar.JULY     ] = "Jul";
+        smonths[Calendar.AUGUST   ] = "Aug";
+        smonths[Calendar.SEPTEMBER] = "Sep";
+        smonths[Calendar.OCTOBER  ] = "Oct";
+        smonths[Calendar.NOVEMBER ] = "Nov";
+        smonths[Calendar.DECEMBER ] = "Dec";
+
+        customSyms.setShortWeekdays(sweekdays);
+        customSyms.setShortMonths(smonths);
+
+        return customSyms;
+    }
+
+    /**
+     * 日付文字列をパースする。
+     * @param txt 文字列
+     * @return エポック時刻(msec)。不正な文字列の場合は負の数を返す。
+     */
+    public static long parseToEpoch(String txt){
+        Date date = parseToDate(txt);
+        if(date == null) return -1L;
+
+        long result = date.getTime();
+
+        return result;
+    }
+
+    /**
+     * 日付文字列をパースする。
+     * @param txt 文字列
+     * @return 日付。不正な文字列の場合はnullを返す。
+     */
+    public static Date parseToDate(String txt){
+        Date result;
+
+        try{
+            synchronized(PARSER){
+                result = PARSER.parse(txt);
+            }
+        }catch(ParseException e){
+            return null;
+        }
+
+        return result;
+    }
+
+}
diff --git a/src/test/java/jp/sfjp/jindolf/net/AccountCookieTest.java b/src/test/java/jp/sfjp/jindolf/net/AccountCookieTest.java
new file mode 100644 (file)
index 0000000..bbb6c94
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * AccountCookie Test
+ *
+ * Copyright(c) 2012 olyutorskii
+ */
+package jp.sfjp.jindolf.net;
+
+import java.net.URI;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class AccountCookieTest {
+
+    public AccountCookieTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() {
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of chopWsp method, of class AccountCookie.
+     */
+    @Test
+    public void testChopWsp_String() {
+        System.out.println("chopWsp");
+
+        String result;
+
+        result = AccountCookie.chopWsp("  abc   ");
+        assertEquals("abc", result);
+
+        result = AccountCookie.chopWsp("abc");
+        assertEquals("abc", result);
+
+        result = AccountCookie.chopWsp("   abc");
+        assertEquals("abc", result);
+
+        result = AccountCookie.chopWsp("abc   ");
+        assertEquals("abc", result);
+
+        result = AccountCookie.chopWsp("a b c");
+        assertEquals("a b c", result);
+
+        result = AccountCookie.chopWsp("\t abc \t");
+        assertEquals("abc", result);
+
+        result = AccountCookie.chopWsp("");
+        assertEquals("", result);
+
+        result = AccountCookie.chopWsp("   ");
+        assertEquals("", result);
+
+        result = AccountCookie.chopWsp(null);
+        assertNull(result);
+
+        return;
+    }
+
+    /**
+     * Test of splitPair method, of class AccountCookie.
+     */
+    @Test
+    public void testSplitPair_String() {
+        System.out.println("splitPair");
+
+        String[] result;
+
+        result = AccountCookie.splitPair("a=b");
+        assertEquals(2, result.length);
+        assertEquals("a", result[0]);
+        assertEquals("b", result[1]);
+
+        result = AccountCookie.splitPair("=b");
+        assertEquals(2, result.length);
+        assertEquals("", result[0]);
+        assertEquals("b", result[1]);
+
+        result = AccountCookie.splitPair("a=");
+        assertEquals(2, result.length);
+        assertEquals("a", result[0]);
+        assertEquals("", result[1]);
+
+        result = AccountCookie.splitPair("=");
+        assertEquals(2, result.length);
+        assertEquals("", result[0]);
+        assertEquals("", result[1]);
+
+        result = AccountCookie.splitPair("==");
+        assertEquals(2, result.length);
+        assertEquals("", result[0]);
+        assertEquals("=", result[1]);
+
+        result = AccountCookie.splitPair("a===b");
+        assertEquals(2, result.length);
+        assertEquals("a", result[0]);
+        assertEquals("==b", result[1]);
+
+        result = AccountCookie.splitPair(" a = b ");
+        assertEquals(2, result.length);
+        assertEquals("a", result[0]);
+        assertEquals("b", result[1]);
+
+        result = AccountCookie.splitPair("a");
+        assertEquals(2, result.length);
+        assertEquals("a", result[0]);
+        assertNull(result[1]);
+
+        result = AccountCookie.splitPair("");
+        assertEquals(2, result.length);
+        assertEquals("", result[0]);
+        assertNull(result[1]);
+
+        return;
+    }
+
+    /**
+     * Test of createCookie method, of class AccountCookie.
+     */
+    @Test
+    public void testCreateCookie_String() {
+        System.out.println("createCookie");
+
+        String cookieSource;
+        AccountCookie result;
+
+        cookieSource =
+                  "login=%22XXX%22;"
+                + " path=/;"
+                + " expires=Sun, 09 Sep 2012 14:16:26 GMT";
+
+        result = AccountCookie.createCookie(cookieSource);
+
+        assertEquals("%22XXX%22", result.getLoginData());
+        assertEquals(URI.create("/"), result.getPathURI());
+        assertEquals(1347200186000L, result.getExpiredTime());
+
+        assertFalse(result.hasExpired(1347200185999L));
+        assertFalse(result.hasExpired(1347200186000L));
+        assertTrue (result.hasExpired(1347200186001L));
+
+        return;
+    }
+
+}
diff --git a/src/test/java/jp/sfjp/jindolf/net/CookieDateParserTest.java b/src/test/java/jp/sfjp/jindolf/net/CookieDateParserTest.java
new file mode 100644 (file)
index 0000000..0f941db
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * CookieDateParser Test
+ *
+ * Copyright(c) 2012 olyutorskii
+ */
+package jp.sfjp.jindolf.net;
+
+import java.util.Date;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class CookieDateParserTest {
+
+    public CookieDateParserTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() {
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of parseToEpoch method, of class CookieDateParser.
+     */
+    @Test
+    public void testParseToEpoch() {
+        System.out.println("parseToEpoch");
+
+        long result;
+
+        result = CookieDateParser
+                .parseToEpoch("Thu, 1 Jan 1970 00:00:00 GMT");
+        assertEquals(0L, result);
+
+        result = CookieDateParser
+                .parseToEpoch("Thu, 26 Jun 2008 06:44:34 GMT");
+        assertEquals(1214462674000L, result);
+
+        result = CookieDateParser
+                .parseToEpoch("Thu, 26 Jun 2008 06:44:34 JST");
+        assertEquals(1214430274000L, result);
+
+        result = CookieDateParser
+                .parseToEpoch("ThuX, 26 Jun 2008 06:44:34 JST");
+        assertTrue(result < 0L);
+
+        return;
+    }
+
+    /**
+     * Test of parseToDate method, of class CookieDateParser.
+     */
+    @Test
+    public void testParseToDate() {
+        System.out.println("parseToDate");
+
+        Date result;
+
+        result = CookieDateParser
+                .parseToDate("Thu, 1 Jan 1970 00:00:00 GMT");
+        assertEquals(new Date(0L), result);
+
+        result = CookieDateParser
+                .parseToDate("Thu, 26 Jun 2008 06:44:34 GMT");
+        assertEquals(new Date(1214462674000L), result);
+
+        result = CookieDateParser
+                .parseToDate("ThuX, 26 Jun 2008 06:44:34 GMT");
+        assertNull(result);
+
+        return;
+    }
+
+}