1b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook/*
2b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * Copyright (C) 2010 The Android Open Source Project
3b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook *
4b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * Licensed under the Apache License, Version 2.0 (the "License");
5b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * you may not use this file except in compliance with the License.
6b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * You may obtain a copy of the License at
7b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook *
8b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook *      http://www.apache.org/licenses/LICENSE-2.0
9b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook *
10b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * Unless required by applicable law or agreed to in writing, software
11b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * distributed under the License is distributed on an "AS IS" BASIS,
12b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * See the License for the specific language governing permissions and
14b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook * limitations under the License.
15b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook */
16b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
17b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrookpackage com.android.common;
18b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
19b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrookimport android.test.suitebuilder.annotation.SmallTest;
20b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
214c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décampsimport junit.framework.TestCase;
224c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps
23b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrookimport java.util.HashMap;
24b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrookimport java.util.Map;
25b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
26b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrookpublic class Rfc822ValidatorTest extends TestCase {
274c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps    static final String[] VALID_EMAILS = new String[] {
284c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a@example.org", "b@exemple.fr", "c@d.e-f",
294c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "Very.Common@example.org",
304c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "john@EXAMPLE.ORG",
314c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "john@a123b.c-d.dept.example.com",
324c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "xn--r8jz45g@example.com",
334c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "disposable.style.email.with+symbol@example.com",
344c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "other.email-with-dash@example.com",
354c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "!#$%&'*+-/=?^_`{}|~@example.com",  // Use of allowed special characters.
364c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a@domain-label-cannot-be-longer-than-63-chars-and-this-is-maximum.example.com",
374c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // Valid de facto, even if RFC doesn't allow it.
384c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a..b@example.com", ".a@example.com", "b.@example.com",
394c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // Punycode is an ASCII representation of International domain names.
404c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "john.doe@xn--r8jz45g.xn--zckzah",
414c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "john.doe@XN--R8JZ45G.XN--ZXKZAH",
424c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "xn--r8jz45g@xn--r8jz45g.XN--ZXKZAH",
434c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // Quoted address.
444c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // TODO(regisd) Fix Rfc822Tokenizer which loses the quotes.
454c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // "\"much.more unusual\"",
464c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // "\"very.unusual.@.unusual.com\""
474c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps
484c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // Valid only in new Internalized email address.
494c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps             "a@\u00E9.example.com",
504c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            //"みんな@例え.テスト",
514c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "\u307F\u3093\u306A@\u4F8B\u3048.\u30C6\u30B9\u30C8",
524c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // "test@test.テスト", // Unicode in TLD only.
534c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "everybody@example.\u30C6\u30B9\u30C8",
544c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // "test@例え.test", // Unicode in domain only.
554c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "everybody@\u4F8B\u3048.test",
564c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // "みんな@example.com" // Unicode in localpart only.
574c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "\u307F\u3093\u306A@example.test"
584c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps    };
594c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps
604c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps    static final String[] INVALID_EMAILS = new String[] {
614c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a", "example.com", "john.example.com", // Missing at sign.
624c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a b", "a space@example.com", // Space not allowed.
634c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // Invalid domain.
644c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "john@example..com", "a@b", "a@-b.com", "a@b-.com", "a@b.c",
654c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a@a123456789-123456789-123456789-123456789-123456789-123456789-bcd.example.com",
664c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // Invalid characters in domain as per RFC 1034 and RFC 1035,
674c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // even if these characters are in RFC5322's domain production.
684c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a@d_e.fg", "a@d!e.fg", "a@d#e.fg", "a@d$e.fg", "a@d%e.fg", "a@d&e.fg", "a@d'e.fg",
694c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a@d*e.fg", "a@d+e.fg", "a@d/e.fg", "a@d=e.fg", "a@d?e.fg", "a@d^e.fg", "a@d{}e.fg",
704c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "a@d|e.fg", "a@d~e.fg",
714c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // The domain is too long
724c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "no@domain-label-cannot-be-longer-than-63-chars-but-this-is-64-chars.com",
734c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "john@doe@example.com", // @ must be unique.
744c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // Incorrect double quote.
754c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // TODO(regisd): Fix Rfc822tokenizer which strips the quotes
764c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            // "just\"not\"right@example.com", "\"just.not\\\"@example.com",
774c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps            "this\\ still\\\"not\\\\allowed@example.com"
784c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps    };
79b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
80b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook    @SmallTest
81b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook    public void testEmailValidator() {
82b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        Rfc822Validator validator = new Rfc822Validator("gmail.com");
83b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
844c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps        for (String email : VALID_EMAILS) {
85b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook            assertTrue(email + " should be a valid email address", validator.isValid(email));
86b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        }
87b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
884c384ab3ae7621e602a95aeac6e527a52bb5598cRégis Décamps        for (String email : INVALID_EMAILS) {
89b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook            assertFalse(email + " should not be a valid email address", validator.isValid(email));
90b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        }
91b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
92b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        Map<String, String> fixes = new HashMap<String, String>();
93b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        fixes.put("a", "<a@gmail.com>");
94b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        fixes.put("a b", "<ab@gmail.com>");
95b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        fixes.put("a@b", "<a@b>");
96490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("()~><@not.work", "");
97490556a764a879cd0eaff358e90705cc1335c92eErik
98490556a764a879cd0eaff358e90705cc1335c92eErik        for (Map.Entry<String, String> e : fixes.entrySet()) {
99490556a764a879cd0eaff358e90705cc1335c92eErik            assertEquals(e.getValue(), validator.fixText(e.getKey()).toString());
100490556a764a879cd0eaff358e90705cc1335c92eErik        }
101490556a764a879cd0eaff358e90705cc1335c92eErik    }
102490556a764a879cd0eaff358e90705cc1335c92eErik
103490556a764a879cd0eaff358e90705cc1335c92eErik    @SmallTest
104490556a764a879cd0eaff358e90705cc1335c92eErik    public void testEmailValidatorNullDomain() {
105490556a764a879cd0eaff358e90705cc1335c92eErik        Rfc822Validator validator = new Rfc822Validator(null);
106490556a764a879cd0eaff358e90705cc1335c92eErik
107490556a764a879cd0eaff358e90705cc1335c92eErik        Map<String, String> fixes = new HashMap<String, String>();
108490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a", "<a>");
109490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a b", "<a b>");
110490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a@b", "<a@b>");
111490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a@b.com", "<a@b.com>"); // this one is correct
112490556a764a879cd0eaff358e90705cc1335c92eErik
113490556a764a879cd0eaff358e90705cc1335c92eErik        for (Map.Entry<String, String> e : fixes.entrySet()) {
114490556a764a879cd0eaff358e90705cc1335c92eErik            assertEquals(e.getValue(), validator.fixText(e.getKey()).toString());
115490556a764a879cd0eaff358e90705cc1335c92eErik        }
116490556a764a879cd0eaff358e90705cc1335c92eErik    }
117490556a764a879cd0eaff358e90705cc1335c92eErik
118490556a764a879cd0eaff358e90705cc1335c92eErik    @SmallTest
119490556a764a879cd0eaff358e90705cc1335c92eErik    public void testEmailValidatorRemoveInvalid() {
120490556a764a879cd0eaff358e90705cc1335c92eErik        Rfc822Validator validator = new Rfc822Validator("google.com");
121490556a764a879cd0eaff358e90705cc1335c92eErik        validator.setRemoveInvalid(true);
122490556a764a879cd0eaff358e90705cc1335c92eErik
123490556a764a879cd0eaff358e90705cc1335c92eErik        Map<String, String> fixes = new HashMap<String, String>();
124490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a", "");
125490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a b", "");
126490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a@b", "");
127490556a764a879cd0eaff358e90705cc1335c92eErik        fixes.put("a@b.com", "<a@b.com>"); // this one is correct
128b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook
129b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        for (Map.Entry<String, String> e : fixes.entrySet()) {
130b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook            assertEquals(e.getValue(), validator.fixText(e.getKey()).toString());
131b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook        }
132b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook    }
133b4f5e0e5755938f2be9a2f1a1a6609b018c530adPaul Westbrook}
134