/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openstreetmap.josm.data.validation.routines; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Locale; import org.junit.Before; import org.junit.Test; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.validation.routines.DomainValidator.ArrayType; /** * Tests for the DomainValidator. * * @version $Revision: 1741724 $ */ public class DomainValidatorTest { private DomainValidator validator; /** * Setup test. */ @Before public void setUp() { validator = DomainValidator.getInstance(); DomainValidator.clearTLDOverrides(); // N.B. this clears the inUse flag, allowing overrides } /** * Test valid domains. */ @Test public void testValidDomains() { assertTrue("apache.org should validate", validator.isValid("apache.org")); assertTrue("www.google.com should validate", validator.isValid("www.google.com")); assertTrue("test-domain.com should validate", validator.isValid("test-domain.com")); assertTrue("test---domain.com should validate", validator.isValid("test---domain.com")); assertTrue("test-d-o-m-ain.com should validate", validator.isValid("test-d-o-m-ain.com")); assertTrue("two-letter domain label should validate", validator.isValid("as.uk")); assertTrue("case-insensitive ApAchE.Org should validate", validator.isValid("ApAchE.Org")); assertTrue("single-character domain label should validate", validator.isValid("z.com")); assertTrue("i.have.an-example.domain.name should validate", validator.isValid("i.have.an-example.domain.name")); } /** * Test invalid domains. */ @Test public void testInvalidDomains() { assertFalse("bare TLD .org shouldn't validate", validator.isValid(".org")); assertFalse("domain name with spaces shouldn't validate", validator.isValid(" apache.org ")); assertFalse("domain name containing spaces shouldn't validate", validator.isValid("apa che.org")); assertFalse("domain name starting with dash shouldn't validate", validator.isValid("-testdomain.name")); assertFalse("domain name ending with dash shouldn't validate", validator.isValid("testdomain-.name")); assertFalse("domain name starting with multiple dashes shouldn't validate", validator.isValid("---c.com")); assertFalse("domain name ending with multiple dashes shouldn't validate", validator.isValid("c--.com")); assertFalse("domain name with invalid TLD shouldn't validate", validator.isValid("apache.rog")); assertFalse("URL shouldn't validate", validator.isValid("http://www.apache.org")); assertFalse("Empty string shouldn't validate as domain name", validator.isValid(" ")); assertFalse("Null shouldn't validate as domain name", validator.isValid(null)); } /** * Test top-level domains. */ @Test public void testTopLevelDomains() { // infrastructure TLDs assertTrue(".arpa should validate as iTLD", validator.isValidInfrastructureTld(".arpa")); assertFalse(".com shouldn't validate as iTLD", validator.isValidInfrastructureTld(".com")); // generic TLDs assertTrue(".name should validate as gTLD", validator.isValidGenericTld(".name")); assertFalse(".us shouldn't validate as gTLD", validator.isValidGenericTld(".us")); // country code TLDs assertTrue(".uk should validate as ccTLD", validator.isValidCountryCodeTld(".uk")); assertFalse(".org shouldn't validate as ccTLD", validator.isValidCountryCodeTld(".org")); // case-insensitive assertTrue(".COM should validate as TLD", validator.isValidTld(".COM")); assertTrue(".BiZ should validate as TLD", validator.isValidTld(".BiZ")); // corner cases assertFalse("invalid TLD shouldn't validate", validator.isValid(".nope")); // TODO this is not guaranteed invalid forever assertFalse("empty string shouldn't validate as TLD", validator.isValid("")); assertFalse("null shouldn't validate as TLD", validator.isValid(null)); } /** * Test "allow local" parameter. */ @Test public void testAllowLocal() { DomainValidator noLocal = DomainValidator.getInstance(false); DomainValidator allowLocal = DomainValidator.getInstance(true); // Default is false, and should use singletons assertEquals(noLocal, validator); // Default won't allow local assertFalse("localhost.localdomain should validate", noLocal.isValid("localhost.localdomain")); assertFalse("localhost should validate", noLocal.isValid("localhost")); // But it may be requested assertTrue("localhost.localdomain should validate", allowLocal.isValid("localhost.localdomain")); assertTrue("localhost should validate", allowLocal.isValid("localhost")); assertTrue("hostname should validate", allowLocal.isValid("hostname")); assertTrue("machinename should validate", allowLocal.isValid("machinename")); // Check the localhost one with a few others assertTrue("apache.org should validate", allowLocal.isValid("apache.org")); assertFalse("domain name with spaces shouldn't validate", allowLocal.isValid(" apache.org ")); } /** * Test IDN. */ @Test public void testIDN() { assertTrue("b\u00fccher.ch in IDN should validate", validator.isValid("www.xn--bcher-kva.ch")); } /** * Test IDN with Java >= 6. */ @Test public void testIDNJava6OrLater() { String version = System.getProperty("java.version"); if (version.compareTo("1.6") < 0) { System.out.println("Cannot run Unicode IDN tests"); return; // Cannot run the test } // xn--d1abbgf6aiiy.xn--p1ai http://президент.рф assertTrue("b\u00fccher.ch should validate", validator.isValid("www.b\u00fccher.ch")); assertTrue("xn--d1abbgf6aiiy.xn--p1ai should validate", validator.isValid("xn--d1abbgf6aiiy.xn--p1ai")); assertTrue("президент.рф should validate", validator.isValid("президент.рф")); assertFalse("www.\uFFFD.ch FFFD should fail", validator.isValid("www.\uFFFD.ch")); } /** * RFC2396: domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum */ @Test public void testRFC2396domainlabel() { // use fixed valid TLD assertTrue("a.ch should validate", validator.isValid("a.ch")); assertTrue("9.ch should validate", validator.isValid("9.ch")); assertTrue("az.ch should validate", validator.isValid("az.ch")); assertTrue("09.ch should validate", validator.isValid("09.ch")); assertTrue("9-1.ch should validate", validator.isValid("9-1.ch")); assertFalse("91-.ch should not validate", validator.isValid("91-.ch")); assertFalse("-.ch should not validate", validator.isValid("-.ch")); } /** * RFC2396 toplabel = alpha | alpha *( alphanum | "-" ) alphanum */ @Test public void testRFC2396toplabel() { // These tests use non-existent TLDs so currently need to use a package protected method assertTrue("a.c (alpha) should validate", validator.isValidDomainSyntax("a.c")); assertTrue("a.cc (alpha alpha) should validate", validator.isValidDomainSyntax("a.cc")); assertTrue("a.c9 (alpha alphanum) should validate", validator.isValidDomainSyntax("a.c9")); assertTrue("a.c-9 (alpha - alphanum) should validate", validator.isValidDomainSyntax("a.c-9")); assertTrue("a.c-z (alpha - alpha) should validate", validator.isValidDomainSyntax("a.c-z")); assertFalse("a.9c (alphanum alpha) should fail", validator.isValidDomainSyntax("a.9c")); assertFalse("a.c- (alpha -) should fail", validator.isValidDomainSyntax("a.c-")); assertFalse("a.- (-) should fail", validator.isValidDomainSyntax("a.-")); assertFalse("a.-9 (- alphanum) should fail", validator.isValidDomainSyntax("a.-9")); } /** * rfc1123 */ @Test public void testDomainNoDots() { assertTrue("a (alpha) should validate", validator.isValidDomainSyntax("a")); assertTrue("9 (alphanum) should validate", validator.isValidDomainSyntax("9")); assertTrue("c-z (alpha - alpha) should validate", validator.isValidDomainSyntax("c-z")); assertFalse("c- (alpha -) should fail", validator.isValidDomainSyntax("c-")); assertFalse("-c (- alpha) should fail", validator.isValidDomainSyntax("-c")); assertFalse("- (-) should fail", validator.isValidDomainSyntax("-")); } /** * Non-regression test for VALIDATOR-297 */ @Test public void testValidator297() { assertTrue("xn--d1abbgf6aiiy.xn--p1ai should validate", validator.isValid("xn--d1abbgf6aiiy.xn--p1ai")); // This uses a valid TLD } /** * Non-regression test for VALIDATOR-306 * labels are a max of 63 chars and domains 253 */ @Test public void testValidator306() { final String longString = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789A"; assertEquals(63, longString.length()); // 26 * 2 + 11 assertTrue("63 chars label should validate", validator.isValidDomainSyntax(longString+".com")); assertFalse("64 chars label should fail", validator.isValidDomainSyntax(longString+"x.com")); assertTrue("63 chars TLD should validate", validator.isValidDomainSyntax("test."+longString)); assertFalse("64 chars TLD should fail", validator.isValidDomainSyntax("test.x"+longString)); final String longDomain = longString + "." + longString + "." + longString + "." + longString.substring(0, 61); assertEquals(253, longDomain.length()); assertTrue("253 chars domain should validate", validator.isValidDomainSyntax(longDomain)); assertFalse("254 chars domain should fail", validator.isValidDomainSyntax(longDomain+"x")); } /** * Check that IDN.toASCII behaves as it should (when wrapped by DomainValidator.unicodeToASCII) * Tests show that method incorrectly trims a trailing "." character */ @Test public void testUnicodeToASCII() { String[] asciidots = { "", ",", ".", // fails IDN.toASCII, but should pass wrapped version "a.", // ditto "a.b", "a..b", "a...b", ".a", "..a", }; for (String s : asciidots) { assertEquals(s, DomainValidator.unicodeToASCII(s)); } // RFC3490 3.1. 1) // Whenever dots are used as label separators, the following // characters MUST be recognized as dots: U+002E (full stop), U+3002 // (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61 // (halfwidth ideographic full stop). final String[][] otherDots = { {"b\u3002", "b."}, {"b\uFF0E", "b."}, {"b\uFF61", "b."}, {"\u3002", "."}, {"\uFF0E", "."}, {"\uFF61", "."}, }; for (String[] s : otherDots) { assertEquals(s[1], DomainValidator.unicodeToASCII(s[0])); } } /** * Check array is sorted and is lower-case * @throws Exception if an error occurs */ @Test public void test_INFRASTRUCTURE_TLDS_sortedAndLowerCase() throws Exception { final boolean sorted = isSortedLowerCase("INFRASTRUCTURE_TLDS"); assertTrue(sorted); } /** * Check array is sorted and is lower-case * @throws Exception if an error occurs */ @Test public void test_COUNTRY_CODE_TLDS_sortedAndLowerCase() throws Exception { final boolean sorted = isSortedLowerCase("COUNTRY_CODE_TLDS"); assertTrue(sorted); } /** * Check array is sorted and is lower-case * @throws Exception if an error occurs */ @Test public void test_GENERIC_TLDS_sortedAndLowerCase() throws Exception { final boolean sorted = isSortedLowerCase("GENERIC_TLDS"); assertTrue(sorted); } /** * Check array is sorted and is lower-case * @throws Exception if an error occurs */ @Test public void test_LOCAL_TLDS_sortedAndLowerCase() throws Exception { final boolean sorted = isSortedLowerCase("LOCAL_TLDS"); assertTrue(sorted); } /** * Test enum visibility */ @Test public void testEnumIsPublic() { assertTrue(Modifier.isPublic(DomainValidator.ArrayType.class.getModifiers())); } /** * Test update base arrays */ @Test public void testUpdateBaseArrays() { try { DomainValidator.updateTLDOverride(ArrayType.COUNTRY_CODE_RO, new String[]{"com"}); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException iae) { // expected Main.debug(iae.getMessage()); } try { DomainValidator.updateTLDOverride(ArrayType.GENERIC_RO, new String[]{"com"}); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException iae) { // expected Main.debug(iae.getMessage()); } try { DomainValidator.updateTLDOverride(ArrayType.INFRASTRUCTURE_RO, new String[]{"com"}); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException iae) { // expected Main.debug(iae.getMessage()); } try { DomainValidator.updateTLDOverride(ArrayType.LOCAL_RO, new String[]{"com"}); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException iae) { // expected Main.debug(iae.getMessage()); } } /** * Test get array. */ @Test public void testGetArray() { assertNotNull(DomainValidator.getTLDEntries(ArrayType.COUNTRY_CODE_MINUS)); assertNotNull(DomainValidator.getTLDEntries(ArrayType.COUNTRY_CODE_PLUS)); assertNotNull(DomainValidator.getTLDEntries(ArrayType.GENERIC_MINUS)); assertNotNull(DomainValidator.getTLDEntries(ArrayType.GENERIC_PLUS)); assertNotNull(DomainValidator.getTLDEntries(ArrayType.COUNTRY_CODE_RO)); assertNotNull(DomainValidator.getTLDEntries(ArrayType.GENERIC_RO)); assertNotNull(DomainValidator.getTLDEntries(ArrayType.INFRASTRUCTURE_RO)); assertNotNull(DomainValidator.getTLDEntries(ArrayType.LOCAL_RO)); } /** * Test update country code. */ @Test public void testUpdateCountryCode() { assertFalse(validator.isValidCountryCodeTld("com")); // cannot be valid DomainValidator.updateTLDOverride(ArrayType.COUNTRY_CODE_PLUS, new String[]{"com"}); assertTrue(validator.isValidCountryCodeTld("com")); // it is now! DomainValidator.updateTLDOverride(ArrayType.COUNTRY_CODE_MINUS, new String[]{"com"}); assertFalse(validator.isValidCountryCodeTld("com")); // show that minus overrides the rest assertTrue(validator.isValidCountryCodeTld("ch")); DomainValidator.updateTLDOverride(ArrayType.COUNTRY_CODE_MINUS, new String[]{"ch"}); assertFalse(validator.isValidCountryCodeTld("ch")); DomainValidator.updateTLDOverride(ArrayType.COUNTRY_CODE_MINUS, new String[]{"xx"}); assertTrue(validator.isValidCountryCodeTld("ch")); } /** * Test update generic. */ @Test public void testUpdateGeneric() { assertFalse(validator.isValidGenericTld("ch")); // cannot be valid DomainValidator.updateTLDOverride(ArrayType.GENERIC_PLUS, new String[]{"ch"}); assertTrue(validator.isValidGenericTld("ch")); // it is now! DomainValidator.updateTLDOverride(ArrayType.GENERIC_MINUS, new String[]{"ch"}); assertFalse(validator.isValidGenericTld("ch")); // show that minus overrides the rest assertTrue(validator.isValidGenericTld("com")); DomainValidator.updateTLDOverride(ArrayType.GENERIC_MINUS, new String[]{"com"}); assertFalse(validator.isValidGenericTld("com")); DomainValidator.updateTLDOverride(ArrayType.GENERIC_MINUS, new String[]{"xx"}); // change the minus list assertTrue(validator.isValidGenericTld("com")); } /** * Test cannot update. */ @Test public void testCannotUpdate() { DomainValidator.updateTLDOverride(ArrayType.GENERIC_PLUS, new String[]{"ch"}); // OK DomainValidator dv = DomainValidator.getInstance(); assertNotNull(dv); try { DomainValidator.updateTLDOverride(ArrayType.GENERIC_PLUS, new String[]{"ch"}); fail("Expected IllegalStateException"); } catch (IllegalStateException ise) { // expected Main.debug(ise.getMessage()); } } private static boolean isSortedLowerCase(String arrayName) throws Exception { Field f = DomainValidator.class.getDeclaredField(arrayName); final boolean isPrivate = Modifier.isPrivate(f.getModifiers()); if (isPrivate) { f.setAccessible(true); } String[] array = (String[]) f.get(null); try { return isSortedLowerCase(arrayName, array); } finally { if (isPrivate) { f.setAccessible(false); } } } private static boolean isLowerCase(String string) { return string.equals(string.toLowerCase(Locale.ENGLISH)); } // Check if an array is strictly sorted - and lowerCase private static boolean isSortedLowerCase(String name, String[] array) { boolean sorted = true; boolean strictlySorted = true; final int length = array.length; boolean lowerCase = isLowerCase(array[length-1]); // Check the last entry for (int i = 0; i < length-1; i++) { // compare all but last entry with next final String entry = array[i]; final String nextEntry = array[i+1]; final int cmp = entry.compareTo(nextEntry); if (cmp > 0) { // out of order System.out.println("Out of order entry: " + entry + " < " + nextEntry + " in " + name); sorted = false; } else if (cmp == 0) { strictlySorted = false; System.out.println("Duplicated entry: " + entry + " in " + name); } if (!isLowerCase(entry)) { System.out.println("Non lowerCase entry: " + entry + " in " + name); lowerCase = false; } } return sorted && strictlySorted && lowerCase; } /** * Unit test of {@link DomainValidator#getValidatorName}. */ @Test public void testValidatorName() { assertNull(DomainValidator.getInstance().getValidatorName()); } }