/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2014-2015 ForgeRock AS.
 */

package com.sun.identity.shared.whitelist;

import static org.testng.AssertJUnit.*;

import java.net.MalformedURLException;
import java.util.Collections;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class URLPatternMatcherTest {

    final URLPatternMatcher urlPatternMatcher = new URLPatternMatcher();

    @Test(dataProvider = "testdata")
    private void performTestAndAssert(String pattern, String url, boolean result) throws MalformedURLException {
        boolean answer = urlPatternMatcher.match(url, Collections.singleton(pattern), true); //wildcard always enabled
        assertEquals(result, answer);
    }

    @DataProvider(name = "testdata")
    public Object[][] testBasic() {
        final String PATTERN_1 = "https://www.google.com/*";
        final String PATTERN_2 = "http://www.good.com";
        final String PATTERN_3 = "http://www.good.com/hello.html";
        final String PATTERN_4 = "*";
        final String PATTERN_5 = "http://*";
        final String PATTERN_6 = "http://www.*:*";
        final String PATTERN_7 = "http://www.*/*";
        final String PATTERN_8 = "http://www.*:*/";
        final String PATTERN_9 = "http://www.*.good.com";
        final String PATTERN_10 = "http://www.*.good.com/";
        final String PATTERN_11 = "http://www.*.good.com/*";
        final String PATTERN_12 = "https://www.*.good.com:*/*";
        final String PATTERN_13 = "https://www.*.good.com:*/-*-/blah";
        final String PATTERN_14 = "*?*";
        final String PATTERN_15 = "http://*.good.com*/*?*";
        final String PATTERN_16 = "/abc*";
        final String PATTERN_17 = "http://www.good.com:80*";
        final String PATTERN_18 = "https://www.*.good.com:443/*";
        final String PATTERN_19 = "https://www.good.com:443/asdf*/blah";
        final String PATTERN_20 = "https://www.good.com:443/asdf-*-/blah";
        final String PATTERN_21 = "http://www.good.com:80/*/hello?*";
        final String PATTERN_22 = "http://www.good.com:80/-*-/-*-/-*-?*";
        final String PATTERN_23 = "http://www.good.com:80/*/*/*?*";

        return new Object[][]{

                //basic test one
            {PATTERN_1, "https://www.google.com:443/hello/there/dance/for/me", true},
            {PATTERN_1, "https://www.google.com:443/hello/there", true},
            {PATTERN_1, "https://www.google.com:443/hello/there/", true},
            {PATTERN_1, "https://www.google.com:443/", true},
            {PATTERN_1, "https://www.google.com:443", true},

                //basic test two
            {PATTERN_2, "http://www.good.com", true},
            {PATTERN_2, "http://www.good.com/", true},
            {PATTERN_2, "http://www.good.com:80", true},
            {PATTERN_2, "http://www.good.com:80/", true},
            {PATTERN_2, "http://www.good.com:80/hello/world", false},
            {PATTERN_2, "https://www.hello.good.com", false},
            {PATTERN_2, "https://www.hello.good.com:443", false},
            {PATTERN_2, "https://www.hello.good.com:443/hello/world", false},
            {PATTERN_2, "http://www.hello.good.com/hello/world", false},
            {PATTERN_2, "http://www.hello.good.com/hello/world?key=value", false},
            {PATTERN_2, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_2, "http://www.hello.good.com:80/hello/world", false},
            {PATTERN_2, "http://www.hello.good.com:80/hello/world?key=value", false},
            {PATTERN_2, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_2, "http://www.hello.bad.com/hello/world/.good.com:80", false},
            {PATTERN_2, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
            {PATTERN_2, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_2, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},

                // tests basic matching with path
            {PATTERN_3, "http://www.good.com", false},
            {PATTERN_3, "http://www.good.com/", false},
            {PATTERN_3, "http://www.good.com:80", false},
            {PATTERN_3, "http://www.good.com:80/", false},
            {PATTERN_3, "http://www.good.com/hello.html", true},
            {PATTERN_3, "http://www.good.com/hello.html/", false},
            {PATTERN_3, "http://www.good.com:80/hello.html", true},
            {PATTERN_3, "http://www.good.com:80/hello.html/", false},
            {PATTERN_3, "http://www.good.com:80/hello/world", false},
            {PATTERN_3, "https://www.hello.good.com", false},
            {PATTERN_3, "https://www.hello.good.com:443", false},
            {PATTERN_3, "https://www.hello.good.com:443/hello/world", false},
            {PATTERN_3, "http://www.hello.good.com/hello/world", false},
            {PATTERN_3, "http://www.hello.good.com/hello/world?key=value", false},
            {PATTERN_3, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_3, "http://www.hello.good.com:80/hello/world", false},
            {PATTERN_3, "http://www.hello.good.com:80/hello/world?key=value", false},
            {PATTERN_3, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_3, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
            {PATTERN_3, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
            {PATTERN_3, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_3, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},

                // tests basic wildcards, should match everything except URLs with question marks in path
            {PATTERN_4, "http://www.good.com", true},
            {PATTERN_4, "http://www.good.com/", true},
            {PATTERN_4, "http://www.good.com:80", true},
            {PATTERN_4, "http://www.good.com:80/", true},
            {PATTERN_4, "http://www.good.com:80/hello/world", true},
            {PATTERN_4, "https://www.good.com", true},
            {PATTERN_4, "https://www.good.com/", true},
            {PATTERN_4, "https://www.good.com:443", true},
            {PATTERN_4, "https://www.good.com:443/", true},
            {PATTERN_4, "https://www.good.com:443/hello/world", true},
            {PATTERN_4, "http://www.good.com/hello/world", true},
            {PATTERN_4, "http://www.good.com/hello/world?key=value", false},
            {PATTERN_4, "http://www.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_4, "http://www.good.com:80/hello/world", true},
            {PATTERN_4, "http://www.good.com:80/hello/world?key=value", false},
            {PATTERN_4, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_4, "http://www.bad.com:80/hello/world/.good.com:80", true},
            {PATTERN_4, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", true},

                //testing wildcard in-location. Should only match domain, and default port (with or without trailing slash)
            {PATTERN_5, "http://www.good.com", true},
            {PATTERN_5, "http://www.good.com:80", true},
            {PATTERN_5, "http://www.good.com:80/hello/world", false},
            {PATTERN_5, "https://www.good.com", false},
            {PATTERN_5, "https://www.good.com:443", false},
            {PATTERN_5, "https://www.good.com:443/hello/world", false},
            {PATTERN_5, "http://www.good.com/hello/world", false},
            {PATTERN_5, "http://www.good.com/hello/world?key=value", false},
            {PATTERN_5, "http://www.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_5, "http://www.good.com:80/hello/world", false},
            {PATTERN_5, "http://www.good.com:80/hello/world?key=value", false},
            {PATTERN_5, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_5, "http://www.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_5, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},

                //as above, but allows the port to be anything other than 80
            {PATTERN_6, "http://www.good.com", true},
            {PATTERN_6, "http://www.good.com:80", true},
            {PATTERN_6, "http://www.good.com:80/hello/world", false},
            {PATTERN_6, "https://www.good.com", false},
            {PATTERN_6, "https://www.good.com:443", false},
            {PATTERN_6, "https://www.good.com:443/hello/world", false},
            {PATTERN_6, "http://www.good.com/hello/world", false},
            {PATTERN_6, "http://www.good.com/hello/world?key=value", false},
            {PATTERN_6, "http://www.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_6, "http://www.good.com:80/hello/world", false},
            {PATTERN_6, "http://www.good.com:80/hello/world?key=value", false},
            {PATTERN_6, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_6, "http://www.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_6, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
            {PATTERN_6, "http://bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_6, "http://bad.com:80/hello/world/.good.com:80/hello/world", false},

                //default port, random host and random path of indeterminable length (excluding question mark)
            {PATTERN_7, "http://www.good.com", true},
            {PATTERN_7, "http://www.good.com:80", true},
            {PATTERN_7, "http://www.good.com:80/hello/world", true},
            {PATTERN_7, "https://www.good.com", false},
            {PATTERN_7, "https://www.good.com:443", false},
            {PATTERN_7, "https://www.good.com:443/hello/world", false},
            {PATTERN_7, "http://www.good.com/hello/world", true},
            {PATTERN_7, "http://www.good.com/hello/world?key=value", false},
            {PATTERN_7, "http://www.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_7, "http://www.good.com:80/hello/world", true},
            {PATTERN_7, "http://www.good.com:80/hello/world?key=value", false},
            {PATTERN_7, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_7, "http://www.bad.com:80/hello/world", true},
            {PATTERN_7, "http://www.bad.com", true},
            {PATTERN_7, "http://www.bad.com:80", true},
            {PATTERN_7, "http://www.bad.com:80/hello/world/.good.com:80", true},
            {PATTERN_7, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", true},

                //random domain, random port, no path but allowed to have optional trailing slash
            {PATTERN_8, "http://www.good.com", true},
            {PATTERN_8, "http://www.good.com/", true},
            {PATTERN_8, "http://www.good.com:80", true},
            {PATTERN_8, "http://www.good.com:80/", true},
            {PATTERN_8, "http://www.good.com:80/hello/world", false},
            {PATTERN_8, "https://www.good.com", false},
            {PATTERN_8, "https://www.good.com:443", false},
            {PATTERN_8, "https://www.good.com:443/hello/world", false},
            {PATTERN_8, "http://www.good.com/hello/world", false},
            {PATTERN_8, "http://www.good.com/hello/world?key=value", false},
            {PATTERN_8, "http://www.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_8, "http://www.good.com:80/hello/world", false},
            {PATTERN_8, "http://www.good.com:80/hello/world?key=value", false},
            {PATTERN_8, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_8, "http://www.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_8, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},

                //random subdomain (but only so long as it's actually a subdomain and not part of the path)
            {PATTERN_9, "http://www.good.com", false},
            {PATTERN_9, "http://www.good.com:80", false},
            {PATTERN_9, "http://www.good.com:80/hello/world", false},
            {PATTERN_9, "http://www.hello.good.com", true},
            {PATTERN_9, "http://www.hello.good.com/", true},
            {PATTERN_9, "http://www.hello.good.com:80", true},
            {PATTERN_9, "http://www.hello.good.com:80/", true},
            {PATTERN_9, "http://www.hello.good.com:80/hello/world", false},
            {PATTERN_9, "https://www.hello.good.com", false},
            {PATTERN_9, "https://www.hello.good.com:443", false},
            {PATTERN_9, "https://www.hello.good.com:443/hello/world", false},
            {PATTERN_9, "http://www.hello.good.com/hello/world", false},
            {PATTERN_9, "http://www.hello.good.com/hello/world?key=value", false},
            {PATTERN_9, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_9, "http://www.hello.good.com:80/hello/world", false},
            {PATTERN_9, "http://www.hello.good.com:80/hello/world?key=value", false},
            {PATTERN_9, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_9, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
            {PATTERN_9, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
            {PATTERN_9, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_9, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},

                //random subdomain with trailing slash, same as previous in different format
            {PATTERN_10, "http://www.hello.good.com", true},
            {PATTERN_10, "http://www.hello.good.com/", true},
            {PATTERN_10, "http://www.hello.good.com:80", true},
            {PATTERN_10, "http://www.hello.good.com:80/", true},
            {PATTERN_10, "http://www.hello.good.com:80/hello/world", false},
            {PATTERN_10, "https://www.hello.good.com", false},
            {PATTERN_10, "https://www.hello.good.com:443", false},
            {PATTERN_10, "https://www.hello.good.com:443/hello/world", false},
            {PATTERN_10, "http://www.hello.good.com/hello/world", false},
            {PATTERN_10, "http://www.hello.good.com/hello/world?key=value", false},
            {PATTERN_10, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_10, "http://www.hello.good.com:80/hello/world", false},
            {PATTERN_10, "http://www.hello.good.com:80/hello/world?key=value", false},
            {PATTERN_10, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_10, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
            {PATTERN_10, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
            {PATTERN_10, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_10, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},

                //random subdomain, default port, indeterminable length path, no question marks
            {PATTERN_11, "http://www.hello.good.com", true},
            {PATTERN_11, "http://www.hello.good.com:80", true},
            {PATTERN_11, "http://www.hello.good.com:80/hello/world", true},
            {PATTERN_11, "https://www.hello.good.com", false},
            {PATTERN_11, "https://www.hello.good.com:443", false},
            {PATTERN_11, "https://www.hello.good.com:443/hello/world", false},
            {PATTERN_11, "http://www.hello.good.com/hello/world", true},
            {PATTERN_11, "http://www.hello.good.com/hello/world?key=value", false},
            {PATTERN_11, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_11, "http://www.hello.good.com:80/hello/world", true},
            {PATTERN_11, "http://www.hello.good.com:80/hello/world?key=value", false},
            {PATTERN_11, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
            {PATTERN_11, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
            {PATTERN_11, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
            {PATTERN_11, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_11, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},

                //random subdomain, random port random path of indeterminable length, no question marks
            {PATTERN_12, "https://www.good.com", false},
            {PATTERN_12, "https://www.good.com/", false},
            {PATTERN_12, "https://www.good.com:443", false},
            {PATTERN_12, "https://www.good.com:443/", false},
            {PATTERN_12, "http://www.hello.good.com/path/", false},
            {PATTERN_12, "https://www.hello.good.com/path/", true},
            {PATTERN_12, "https://www.hello.good.com/", true},
            {PATTERN_12, "https://www.hello.good.com", true},
            {PATTERN_12, "https://www.good.com:443/path/", false},
            {PATTERN_12, "https://www.subdomain.good.com:443/path/", true},
            {PATTERN_12, "https://www.bad.com/.good.com:443/evil", false},
            {PATTERN_12, "https://www.hello.good.com:80/path/", true},
            {PATTERN_12, "https://www.bad.com:443/.good.com:443/evil", false},

                //testing single-level wildcards. After the (random) port, should have a single level before blah
            {PATTERN_13, "https://www.one.good.com", false},
            {PATTERN_13, "https://www.one.good.com:80", false},
            {PATTERN_13, "https://www.good.com/bad", false},
            {PATTERN_13, "https://www.bad.com/.good.com", false},
            {PATTERN_13, "https://www.one.good.com/hello/blah", true},
            {PATTERN_13, "https://www.one.good.com/hello/world/blah", false},
            {PATTERN_13, "https://www.one.good.com/hello/world/also/more/blah", false},

                //allows for anything which contains a question mark in it, regardless of scheme, host or port
            {PATTERN_14, "http://www.good.com", false},
            {PATTERN_14, "http://www.good.com:80", false},
            {PATTERN_14, "http://www.good.com:80/hello/world", false},
            {PATTERN_14, "https://www.good.com", false},
            {PATTERN_14, "https://www.good.com:443", false},
            {PATTERN_14, "https://www.good.com:443/hello/world", false},
            {PATTERN_14, "http://www.good.com/hello/world", false},
            {PATTERN_14, "http://www.good.com/hello/world?key=value", true},
            {PATTERN_14, "http://www.good.com/hello/world?key=value&key2=value2", true},
            {PATTERN_14, "http://www.good.com:80/hello/world", false},
            {PATTERN_14, "http://www.good.com:80/hello/world?", true},
            {PATTERN_14, "http://www.good.com:80/hello/world?key=value", true},
            {PATTERN_14, "http://www.good.com:80/hello/world?key=value&key2=value2", true},
            {PATTERN_14, "http://www.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_14, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},

                //random subdomain, default port, any length path with question mark
            {PATTERN_15, "http://www.good.com", false},
            {PATTERN_15, "http://www.good.com:80", false},
            {PATTERN_15, "http://www.good.com:80/hello/world", false},
            {PATTERN_15, "https://www.good.com", false},
            {PATTERN_15, "https://www.good.com:443", false},
            {PATTERN_15, "https://www.good.com:443/hello/world", false},
            {PATTERN_15, "http://www.good.com/hello/world", false},
            {PATTERN_15, "http://www.good.com/hello/world?key=value", true},
            {PATTERN_15, "http://www.good.com/hello/world?key=value&key2=value2", true},
            {PATTERN_15, "http://www.good.com:80/hello/world", false},
            {PATTERN_15, "http://www.good.com:80/hello/world?key=value", true},
            {PATTERN_15, "http://www.good.com:80/hello/world?key=value&key2=value2", true},
            {PATTERN_15, "http://www.good.com:80/hello/good/bye/world?key=value&key2=value2", true},
            {PATTERN_15, "http://www.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_15, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},

            {PATTERN_16, "http://www.good.com", false},
            {PATTERN_16, "http://www.good.com:80", false},
            {PATTERN_16, "http://www.good.com:80/hello/world", false},
            {PATTERN_16, "http://www.good.com:80/abc/world", false},
            {PATTERN_16, "http://www.good.com:80/abc", false},
            {PATTERN_16, "http://www.good.com/abc", false},
            {PATTERN_16, "https://www.good.com", false},
            {PATTERN_16, "https://www.good.com:443", false},
            {PATTERN_16, "http://www.good.com/hello/world", false},
            {PATTERN_16, "http://www.good.com/hello/world?key=value", false},
            {PATTERN_16, "http://www.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_16, "http://www.good.com:80/hello/world", false},
            {PATTERN_16, "http://www.good.com:80/hello/world?key=value", false},
            {PATTERN_16, "http://www.good.com:80/abc/world?key=value&key2=value2", false},
            {PATTERN_16, "http://www.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_16, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
            {PATTERN_16, "/abc", true},
            {PATTERN_16, "/acb/def/blah", false},
            {PATTERN_16, "/abc/def/blah", true},

                //wildcard after port
            {PATTERN_17, "http://www.good.com", true},
            {PATTERN_17, "http://www.good.com:80", true},
            {PATTERN_17, "http://www.good.com:808", true},
            {PATTERN_17, "http://www.good.com:808/", true},
            {PATTERN_17, "http://www.good.com:808/asdf", false},
            {PATTERN_17, "http://www.good.com:80/hello/world", false},
            {PATTERN_17, "http://www.good.com:80/abc/world", false},
            {PATTERN_17, "http://www.good.com:80/abc", false},
            {PATTERN_17, "http://www.good.com/abc", false},
            {PATTERN_17, "https://www.good.com", false},
            {PATTERN_17, "https://www.good.com:443", false},
            {PATTERN_17, "http://www.good.com/hello/world", false},
            {PATTERN_17, "http://www.good.com/hello/world?key=value", false},
            {PATTERN_17, "http://www.good.com/hello/world?key=value&key2=value2", false},
            {PATTERN_17, "http://www.good.com:80/hello/world?key=value", false},
            {PATTERN_17, "http://www.good.com:80/abc/world?key=value&key2=value2", false},
            {PATTERN_17, "http://www.bad.com:80/hello/world/.good.com:80", false},
            {PATTERN_17, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},

                //any subdomain, any path
            {PATTERN_18, "https://www.good.com", false},
            {PATTERN_18, "https://www.good.com/", false},
            {PATTERN_18, "https://www.bad.good.com/", true},
            {PATTERN_18, "https://www.good.com:443", false},
            {PATTERN_18, "https://www.good.com:443/", false},
            {PATTERN_18, "http://www.hello.good.com/path/", false},
            {PATTERN_18, "https://www.hello.good.com/path/", true},
            {PATTERN_18, "https://www.good.com:443/path/", false},
            {PATTERN_18, "https://www.subdomain.good.com:443/path/", true},
            {PATTERN_18, "https://www.bad.com/.good.com:443/evil", false},
            {PATTERN_18, "https://www.hello.good.com:80/path/", false},
            {PATTERN_18, "https://www.bad.com:443/.good.com:443/evil", false},

                //continuation after "asdf"
            {PATTERN_19, "https://www.good.com", false},
            {PATTERN_19, "https://www.good.com/", false},
            {PATTERN_19, "https://www.bad.good.com/", false},
            {PATTERN_19, "https://www.good.com:443", false},
            {PATTERN_19, "https://www.good.com:443/", false},
            {PATTERN_19, "http://www.hello.good.com/path/", false},
            {PATTERN_19, "https://www.hello.good.com/path/", false},
            {PATTERN_19, "https://www.good.com:443/path/", false},
            {PATTERN_19, "https://www.subdomain.good.com:443/path/", false},
            {PATTERN_19, "https://www.bad.com/.good.com:443/evil", false},
            {PATTERN_19, "http://www.hello.good.com:80/asdf123/path/blah", false},
            {PATTERN_19, "https://www.good.com:443/asdf123/blah", true},
            {PATTERN_19, "https://www.good.com:443/asdf123/456/blah", true},
            {PATTERN_19, "https://www.bad.com:443/.good.com:443/evil", false},

                //continuation after "asdf" stops at first slash
            {PATTERN_20, "https://www.good.com:443/asdf123/blah", true},
            {PATTERN_20, "https://www.good.com:443/asdf123/456/blah", false},

                //any levels before hello, with query params
            {PATTERN_21, "http://www.good.com", false},
            {PATTERN_21, "http://www.good.com:80", false},
            {PATTERN_21, "http://www.good.com:80/hello/bob/hello/?bob=bob", false},
            {PATTERN_21, "http://www.good.com:80/hello/bob/hello?bob=bob", true},
            {PATTERN_21, "http://www.good.com:80/hello/hello?bob=bob", true},
            {PATTERN_21, "http://www.good.com:80/hello/bob?bob=bob", false},
            {PATTERN_21, "http://www.good.com:80/hello/world/", false},
            {PATTERN_21, "http://www.good.com:80/hello/world", false},
            {PATTERN_21, "http://www.good.com:80/hello/?bob=bob", false},

                //optional path-element before question mark, exactly two levels before that
            {PATTERN_22, "http://www.good.com", false},
            {PATTERN_22, "http://www.good.com:80", false},
            {PATTERN_22, "http://www.good.com:80/hello/bob/hello?bob=bob", true},
            {PATTERN_22, "http://www.good.com:80/hello/bob/hello/?bob=bob", true},
            {PATTERN_22, "http://www.good.com:80/hello/bob/hello/again?bob=bob", false},
            {PATTERN_22, "http://www.good.com:80/hello/bob/hello/again/and/again?bob=bob", false},
            {PATTERN_22, "http://www.good.com:80/hello/bob/?bob=bob", true},
            {PATTERN_22, "http://www.good.com:80/hello/bob?bob=bob", true},
            {PATTERN_22, "http://www.good.com:80/hello?bob=bob", false},
            {PATTERN_22, "http://www.good.com:80/hello/world/", false},
            {PATTERN_22, "http://www.good.com:80/hello/world", false},
            {PATTERN_22, "http://www.good.com:80/hello/?bob=bob", false},

                //optional path-element before question mark, two (or more) levels before that (but not fewer)
            {PATTERN_23, "http://www.good.com", false},
            {PATTERN_23, "http://www.good.com:80", false},
            {PATTERN_23, "http://www.good.com:80/hello/bob/hello?bob=bob", true},
            {PATTERN_23, "http://www.good.com:80/hello/bob/hello/?bob=bob", true},
            {PATTERN_23, "http://www.good.com:80/hello/bob/hello/again?bob=bob", true},
            {PATTERN_23, "http://www.good.com:80/hello/bob/hello/again/and/again?bob=bob", true},
            {PATTERN_23, "http://www.good.com:80/hello/bob/?bob=bob", true},
            {PATTERN_23, "http://www.good.com:80/hello/bob?bob=bob", false},
            {PATTERN_23, "http://www.good.com:80/hello?bob=bob", false},
            {PATTERN_23, "http://www.good.com:80/hello/world/", false},
            {PATTERN_23, "http://www.good.com:80/hello/world", false},
            {PATTERN_23, "http://www.good.com:80/hello/?bob=bob", false}
        };
    }
}
