root/extensions/common/url_pattern_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TEST
  2. TEST
  3. TEST
  4. TEST
  5. TEST
  6. TEST
  7. TEST
  8. TEST
  9. TEST
  10. TEST
  11. TEST
  12. TEST
  13. TEST
  14. TEST
  15. TEST
  16. TEST
  17. TEST
  18. TEST
  19. TEST
  20. TEST
  21. TEST
  22. Overlaps
  23. TEST
  24. TEST
  25. TEST
  26. TEST
  27. TEST
  28. TEST
  29. NeitherContains
  30. StrictlyContains
  31. TEST

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/scoped_ptr.h"
#include "extensions/common/url_pattern.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

namespace {

// See url_pattern.h for examples of valid and invalid patterns.

static const int kAllSchemes =
    URLPattern::SCHEME_HTTP |
    URLPattern::SCHEME_HTTPS |
    URLPattern::SCHEME_FILE |
    URLPattern::SCHEME_FTP |
    URLPattern::SCHEME_CHROMEUI |
    URLPattern::SCHEME_EXTENSION |
    URLPattern::SCHEME_FILESYSTEM;

TEST(ExtensionURLPatternTest, ParseInvalid) {
  const struct {
    const char* pattern;
    URLPattern::ParseResult expected_result;
  } kInvalidPatterns[] = {
    { "http", URLPattern::PARSE_ERROR_MISSING_SCHEME_SEPARATOR },
    { "http:", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
    { "http:/", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
    { "about://", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
    { "http://", URLPattern::PARSE_ERROR_EMPTY_HOST },
    { "http:///", URLPattern::PARSE_ERROR_EMPTY_HOST },
    { "http://*foo/bar", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
    { "http://foo.*.bar/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
    { "http://fo.*.ba:123/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
    { "http:/bar", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
    { "http://bar", URLPattern::PARSE_ERROR_EMPTY_PATH },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidPatterns); ++i) {
    URLPattern pattern(URLPattern::SCHEME_ALL);
    EXPECT_EQ(kInvalidPatterns[i].expected_result,
              pattern.Parse(kInvalidPatterns[i].pattern))
        << kInvalidPatterns[i].pattern;
  }
};

TEST(ExtensionURLPatternTest, Ports) {
  const struct {
    const char* pattern;
    URLPattern::ParseResult expected_result;
    const char* expected_port;
  } kTestPatterns[] = {
    { "http://foo:1234/", URLPattern::PARSE_SUCCESS, "1234" },
    { "http://foo:1234/bar", URLPattern::PARSE_SUCCESS, "1234" },
    { "http://*.foo:1234/", URLPattern::PARSE_SUCCESS, "1234" },
    { "http://*.foo:1234/bar", URLPattern::PARSE_SUCCESS,"1234" },
    { "http://:1234/", URLPattern::PARSE_SUCCESS, "1234" },
    { "http://foo:/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
    { "http://foo:*/", URLPattern::PARSE_SUCCESS, "*" },
    { "http://*.foo:/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
    { "http://foo:com/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
    { "http://foo:123456/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
    { "http://foo:80:80/monkey", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
    { "file://foo:1234/bar", URLPattern::PARSE_SUCCESS, "*" },
    { "chrome://foo:1234/bar", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },

    // Port-like strings in the path should not trigger a warning.
    { "http://*/:1234", URLPattern::PARSE_SUCCESS, "*" },
    { "http://*.foo/bar:1234", URLPattern::PARSE_SUCCESS, "*" },
    { "http://foo/bar:1234/path", URLPattern::PARSE_SUCCESS,"*" },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestPatterns); ++i) {
    URLPattern pattern(URLPattern::SCHEME_ALL);
    EXPECT_EQ(kTestPatterns[i].expected_result,
              pattern.Parse(kTestPatterns[i].pattern))
        << "Got unexpected result for URL pattern: "
        << kTestPatterns[i].pattern;
    EXPECT_EQ(kTestPatterns[i].expected_port, pattern.port())
        << "Got unexpected port for URL pattern: " << kTestPatterns[i].pattern;
  }
};

// all pages for a given scheme
TEST(ExtensionURLPatternTest, Match1) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*/*"));
  EXPECT_EQ("http", pattern.scheme());
  EXPECT_EQ("", pattern.host());
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://yahoo.com")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foo")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("https://google.com")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://74.125.127.100/search")));
}

// all domains
TEST(ExtensionURLPatternTest, Match2) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("https://*/foo*"));
  EXPECT_EQ("https", pattern.scheme());
  EXPECT_EQ("", pattern.host());
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("https://www.google.com/foo")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("https://www.google.com/foobar")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("http://www.google.com/foo")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("https://www.google.com/")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("filesystem:https://www.google.com/foobar/")));
}

// subdomains
TEST(URLPatternTest, Match3) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
            pattern.Parse("http://*.google.com/foo*bar"));
  EXPECT_EQ("http", pattern.scheme());
  EXPECT_EQ("google.com", pattern.host());
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo*bar", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foobar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com/foo?bar")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("http://monkey.images.google.com/foooobar")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("http://yahoo.com/foobar")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("filesystem:http://google.com/foo/bar")));
  EXPECT_FALSE(pattern.MatchesURL(
      GURL("filesystem:http://google.com/temporary/foobar")));
}

// glob escaping
TEST(ExtensionURLPatternTest, Match5) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file:///foo?bar\\*baz"));
  EXPECT_EQ("file", pattern.scheme());
  EXPECT_EQ("", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo?bar\\*baz", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo?bar\\hellobaz")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("file:///fooXbar\\hellobaz")));
}

// ip addresses
TEST(ExtensionURLPatternTest, Match6) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://127.0.0.1/*"));
  EXPECT_EQ("http", pattern.scheme());
  EXPECT_EQ("127.0.0.1", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
}

// subdomain matching with ip addresses
TEST(ExtensionURLPatternTest, Match7) {
  URLPattern pattern(kAllSchemes);
  // allowed, but useless
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.0.0.1/*"));
  EXPECT_EQ("http", pattern.scheme());
  EXPECT_EQ("0.0.1", pattern.host());
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  // Subdomain matching is never done if the argument has an IP address host.
  EXPECT_FALSE(pattern.MatchesURL(GURL("http://127.0.0.1")));
};

// unicode
TEST(ExtensionURLPatternTest, Match8) {
  URLPattern pattern(kAllSchemes);
  // The below is the ASCII encoding of the following URL:
  // http://*.\xe1\x80\xbf/a\xc2\x81\xe1*
  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
            pattern.Parse("http://*.xn--gkd/a%C2%81%E1*"));
  EXPECT_EQ("http", pattern.scheme());
  EXPECT_EQ("xn--gkd", pattern.host());
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/a%C2%81%E1*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("http://abc.\xe1\x80\xbf/a\xc2\x81\xe1xyz")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("http://\xe1\x80\xbf/a\xc2\x81\xe1\xe1")));
};

// chrome://
TEST(ExtensionURLPatternTest, Match9) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("chrome://favicon/*"));
  EXPECT_EQ("chrome", pattern.scheme());
  EXPECT_EQ("favicon", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/https://google.com")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("chrome://history")));
};

// *://
TEST(ExtensionURLPatternTest, Match10) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("*://*/*"));
  EXPECT_TRUE(pattern.MatchesScheme("http"));
  EXPECT_TRUE(pattern.MatchesScheme("https"));
  EXPECT_FALSE(pattern.MatchesScheme("chrome"));
  EXPECT_FALSE(pattern.MatchesScheme("file"));
  EXPECT_FALSE(pattern.MatchesScheme("ftp"));
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("file:///foo/bar")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("file://localhost/foo/bar")));
};

// <all_urls>
TEST(ExtensionURLPatternTest, Match11) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("<all_urls>"));
  EXPECT_TRUE(pattern.MatchesScheme("chrome"));
  EXPECT_TRUE(pattern.MatchesScheme("http"));
  EXPECT_TRUE(pattern.MatchesScheme("https"));
  EXPECT_TRUE(pattern.MatchesScheme("file"));
  EXPECT_TRUE(pattern.MatchesScheme("filesystem"));
  EXPECT_TRUE(pattern.MatchesScheme("chrome-extension"));
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_TRUE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo/bar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo/bar")));

  // Make sure the properties are the same when creating an <all_urls> pattern
  // via SetMatchAllURLs and by parsing <all_urls>.
  URLPattern pattern2(kAllSchemes);
  pattern2.SetMatchAllURLs(true);

  EXPECT_EQ(pattern.valid_schemes(), pattern2.valid_schemes());
  EXPECT_EQ(pattern.match_subdomains(), pattern2.match_subdomains());
  EXPECT_EQ(pattern.path(), pattern2.path());
  EXPECT_EQ(pattern.match_all_urls(), pattern2.match_all_urls());
  EXPECT_EQ(pattern.scheme(), pattern2.scheme());
  EXPECT_EQ(pattern.port(), pattern2.port());
  EXPECT_EQ(pattern.GetAsString(), pattern2.GetAsString());
};

// SCHEME_ALL matches all schemes.
TEST(ExtensionURLPatternTest, Match12) {
  URLPattern pattern(URLPattern::SCHEME_ALL);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("<all_urls>"));
  EXPECT_TRUE(pattern.MatchesScheme("chrome"));
  EXPECT_TRUE(pattern.MatchesScheme("http"));
  EXPECT_TRUE(pattern.MatchesScheme("https"));
  EXPECT_TRUE(pattern.MatchesScheme("file"));
  EXPECT_TRUE(pattern.MatchesScheme("filesystem"));
  EXPECT_TRUE(pattern.MatchesScheme("javascript"));
  EXPECT_TRUE(pattern.MatchesScheme("data"));
  EXPECT_TRUE(pattern.MatchesScheme("about"));
  EXPECT_TRUE(pattern.MatchesScheme("chrome-extension"));
  EXPECT_TRUE(pattern.match_subdomains());
  EXPECT_TRUE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo/bar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo/bar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://newtab")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("about:blank")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("about:version")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("data:text/html;charset=utf-8,<html>asdf</html>")));
};

static const struct MatchPatterns {
  const char* pattern;
  const char* matches;
} kMatch13UrlPatternTestCases[] = {
  {"about:*", "about:blank"},
  {"about:blank", "about:blank"},
  {"about:*", "about:version"},
  {"chrome-extension://*/*", "chrome-extension://FTW"},
  {"data:*", "data:monkey"},
  {"javascript:*", "javascript:atemyhomework"},
};

// SCHEME_ALL and specific schemes.
TEST(ExtensionURLPatternTest, Match13) {
  for (size_t i = 0; i < arraysize(kMatch13UrlPatternTestCases); ++i) {
    URLPattern pattern(URLPattern::SCHEME_ALL);
    EXPECT_EQ(URLPattern::PARSE_SUCCESS,
              pattern.Parse(kMatch13UrlPatternTestCases[i].pattern))
        << " while parsing " << kMatch13UrlPatternTestCases[i].pattern;
    EXPECT_TRUE(pattern.MatchesURL(
        GURL(kMatch13UrlPatternTestCases[i].matches)))
        << " while matching " << kMatch13UrlPatternTestCases[i].matches;
  }

  // Negative test.
  URLPattern pattern(URLPattern::SCHEME_ALL);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("data:*"));
  EXPECT_FALSE(pattern.MatchesURL(GURL("about:blank")));
};

// file scheme with empty hostname
TEST(ExtensionURLPatternTest, Match14) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file:///foo*"));
  EXPECT_EQ("file", pattern.scheme());
  EXPECT_EQ("", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo*", pattern.path());
  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo")));
}

// file scheme without hostname part
TEST(ExtensionURLPatternTest, Match15) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file://foo*"));
  EXPECT_EQ("file", pattern.scheme());
  EXPECT_EQ("", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo*", pattern.path());
  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo")));
}

// file scheme with hostname
TEST(ExtensionURLPatternTest, Match16) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file://localhost/foo*"));
  EXPECT_EQ("file", pattern.scheme());
  // Since hostname is ignored for file://.
  EXPECT_EQ("", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo*", pattern.path());
  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo")));
}

// Specific port
TEST(ExtensionURLPatternTest, Match17) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
            pattern.Parse("http://www.example.com:80/foo"));
  EXPECT_EQ("http", pattern.scheme());
  EXPECT_EQ("www.example.com", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo", pattern.path());
  EXPECT_EQ("80", pattern.port());
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo")));
  EXPECT_FALSE(pattern.MatchesURL(
      GURL("filesystem:http://www.example.com:8080/foo/")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("filesystem:http://www.example.com/f/foo")));
}

// Explicit port wildcard
TEST(ExtensionURLPatternTest, Match18) {
  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
            pattern.Parse("http://www.example.com:*/foo"));
  EXPECT_EQ("http", pattern.scheme());
  EXPECT_EQ("www.example.com", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/foo", pattern.path());
  EXPECT_EQ("*", pattern.port());
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo")));
  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo")));
  EXPECT_FALSE(pattern.MatchesURL(
      GURL("filesystem:http://www.example.com:8080/foo/")));
}

// chrome-extension://
TEST(ExtensionURLPatternTest, Match19) {
  URLPattern pattern(URLPattern::SCHEME_EXTENSION);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
            pattern.Parse("chrome-extension://ftw/*"));
  EXPECT_EQ("chrome-extension", pattern.scheme());
  EXPECT_EQ("ftw", pattern.host());
  EXPECT_FALSE(pattern.match_subdomains());
  EXPECT_FALSE(pattern.match_all_urls());
  EXPECT_EQ("/*", pattern.path());
  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome-extension://ftw")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("chrome-extension://ftw/http://google.com")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("chrome-extension://ftw/https://google.com")));
  EXPECT_FALSE(pattern.MatchesURL(GURL("chrome-extension://foobar")));
  EXPECT_TRUE(pattern.MatchesURL(
      GURL("filesystem:chrome-extension://ftw/t/file.txt")));
};

static const struct GetAsStringPatterns {
  const char* pattern;
} kGetAsStringTestCases[] = {
  { "http://www/" },
  { "http://*/*" },
  { "chrome://*/*" },
  { "chrome://newtab/" },
  { "about:*" },
  { "about:blank" },
  { "chrome-extension://*/*" },
  { "chrome-extension://FTW/" },
  { "data:*" },
  { "data:monkey" },
  { "javascript:*" },
  { "javascript:atemyhomework" },
  { "http://www.example.com:8080/foo" },
};

TEST(ExtensionURLPatternTest, GetAsString) {
  for (size_t i = 0; i < arraysize(kGetAsStringTestCases); ++i) {
    URLPattern pattern(URLPattern::SCHEME_ALL);
    EXPECT_EQ(URLPattern::PARSE_SUCCESS,
              pattern.Parse(kGetAsStringTestCases[i].pattern))
        << "Error parsing " << kGetAsStringTestCases[i].pattern;
    EXPECT_EQ(kGetAsStringTestCases[i].pattern,
              pattern.GetAsString());
  }
}

testing::AssertionResult Overlaps(const URLPattern& pattern1,
                                  const URLPattern& pattern2) {
  if (!pattern1.OverlapsWith(pattern2)) {
    return testing::AssertionFailure()
        << pattern1.GetAsString() << " does not overlap " <<
                                     pattern2.GetAsString();
  }
  if (!pattern2.OverlapsWith(pattern1)) {
    return testing::AssertionFailure()
        << pattern2.GetAsString() << " does not overlap " <<
                                     pattern1.GetAsString();
  }
  return testing::AssertionSuccess()
      << pattern1.GetAsString() << " overlaps with " << pattern2.GetAsString();
}

TEST(ExtensionURLPatternTest, Overlaps) {
  URLPattern pattern1(kAllSchemes, "http://www.google.com/foo/*");
  URLPattern pattern2(kAllSchemes, "https://www.google.com/foo/*");
  URLPattern pattern3(kAllSchemes, "http://*.google.com/foo/*");
  URLPattern pattern4(kAllSchemes, "http://*.yahooo.com/foo/*");
  URLPattern pattern5(kAllSchemes, "http://www.yahooo.com/bar/*");
  URLPattern pattern6(kAllSchemes,
                      "http://www.yahooo.com/bar/baz/*");
  URLPattern pattern7(kAllSchemes, "file:///*");
  URLPattern pattern8(kAllSchemes, "*://*/*");
  URLPattern pattern9(URLPattern::SCHEME_HTTPS, "*://*/*");
  URLPattern pattern10(kAllSchemes, "<all_urls>");

  EXPECT_TRUE(Overlaps(pattern1, pattern1));
  EXPECT_FALSE(Overlaps(pattern1, pattern2));
  EXPECT_TRUE(Overlaps(pattern1, pattern3));
  EXPECT_FALSE(Overlaps(pattern1, pattern4));
  EXPECT_FALSE(Overlaps(pattern3, pattern4));
  EXPECT_FALSE(Overlaps(pattern4, pattern5));
  EXPECT_TRUE(Overlaps(pattern5, pattern6));

  // Test that scheme restrictions work.
  EXPECT_TRUE(Overlaps(pattern1, pattern8));
  EXPECT_FALSE(Overlaps(pattern1, pattern9));
  EXPECT_TRUE(Overlaps(pattern1, pattern10));

  // Test that '<all_urls>' includes file URLs, while scheme '*' does not.
  EXPECT_FALSE(Overlaps(pattern7, pattern8));
  EXPECT_TRUE(Overlaps(pattern7, pattern10));

  // Test that wildcard schemes are handled correctly, especially when compared
  // to each-other.
  URLPattern pattern11(kAllSchemes, "http://example.com/*");
  URLPattern pattern12(kAllSchemes, "*://example.com/*");
  URLPattern pattern13(kAllSchemes, "*://example.com/foo/*");
  URLPattern pattern14(kAllSchemes, "*://google.com/*");
  EXPECT_TRUE(Overlaps(pattern8, pattern12));
  EXPECT_TRUE(Overlaps(pattern9, pattern12));
  EXPECT_TRUE(Overlaps(pattern10, pattern12));
  EXPECT_TRUE(Overlaps(pattern11, pattern12));
  EXPECT_TRUE(Overlaps(pattern12, pattern13));
  EXPECT_TRUE(Overlaps(pattern11, pattern13));
  EXPECT_FALSE(Overlaps(pattern14, pattern12));
  EXPECT_FALSE(Overlaps(pattern14, pattern13));
}

TEST(ExtensionURLPatternTest, ConvertToExplicitSchemes) {
  URLPatternList all_urls(URLPattern(
      kAllSchemes,
      "<all_urls>").ConvertToExplicitSchemes());

  URLPatternList all_schemes(URLPattern(
      kAllSchemes,
      "*://google.com/foo").ConvertToExplicitSchemes());

  URLPatternList monkey(URLPattern(
      URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
      URLPattern::SCHEME_FTP,
      "http://google.com/monkey").ConvertToExplicitSchemes());

  ASSERT_EQ(7u, all_urls.size());
  ASSERT_EQ(2u, all_schemes.size());
  ASSERT_EQ(1u, monkey.size());

  EXPECT_EQ("http://*/*", all_urls[0].GetAsString());
  EXPECT_EQ("https://*/*", all_urls[1].GetAsString());
  EXPECT_EQ("file:///*", all_urls[2].GetAsString());
  EXPECT_EQ("ftp://*/*", all_urls[3].GetAsString());
  EXPECT_EQ("chrome://*/*", all_urls[4].GetAsString());

  EXPECT_EQ("http://google.com/foo", all_schemes[0].GetAsString());
  EXPECT_EQ("https://google.com/foo", all_schemes[1].GetAsString());

  EXPECT_EQ("http://google.com/monkey", monkey[0].GetAsString());
}

TEST(ExtensionURLPatternTest, IgnorePorts) {
  std::string pattern_str = "http://www.example.com:8080/foo";
  GURL url("http://www.example.com:1234/foo");

  URLPattern pattern(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse(pattern_str));

  EXPECT_EQ(pattern_str, pattern.GetAsString());
  EXPECT_FALSE(pattern.MatchesURL(url));
}

TEST(ExtensionURLPatternTest, IgnoreMissingBackslashes) {
  std::string pattern_str1 = "http://www.example.com/example";
  std::string pattern_str2 = "http://www.example.com/example/*";
  GURL url1("http://www.example.com/example");
  GURL url2("http://www.example.com/example/");

  URLPattern pattern1(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse(pattern_str1));
  URLPattern pattern2(kAllSchemes);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern2.Parse(pattern_str2));

  // Same patterns should match same urls.
  EXPECT_TRUE(pattern1.MatchesURL(url1));
  EXPECT_TRUE(pattern2.MatchesURL(url2));
  // The not terminated path should match the terminated pattern.
  EXPECT_TRUE(pattern2.MatchesURL(url1));
  // The terminated path however should not match the unterminated pattern.
  EXPECT_FALSE(pattern1.MatchesURL(url2));
}

TEST(ExtensionURLPatternTest, Equals) {
  const struct {
    const char* pattern1;
    const char* pattern2;
    bool expected_equal;
  } kEqualsTestCases[] = {
    // schemes
    { "http://en.google.com/blah/*/foo",
      "https://en.google.com/blah/*/foo",
      false
    },
    { "https://en.google.com/blah/*/foo",
      "https://en.google.com/blah/*/foo",
      true
    },
    { "https://en.google.com/blah/*/foo",
      "ftp://en.google.com/blah/*/foo",
      false
    },

    // subdomains
    { "https://en.google.com/blah/*/foo",
      "https://fr.google.com/blah/*/foo",
      false
    },
    { "https://www.google.com/blah/*/foo",
      "https://*.google.com/blah/*/foo",
      false
    },
    { "https://*.google.com/blah/*/foo",
      "https://*.google.com/blah/*/foo",
      true
    },

    // domains
    { "http://en.example.com/blah/*/foo",
      "http://en.google.com/blah/*/foo",
      false
    },

    // ports
    { "http://en.google.com:8000/blah/*/foo",
      "http://en.google.com/blah/*/foo",
      false
    },
    { "http://fr.google.com:8000/blah/*/foo",
      "http://fr.google.com:8000/blah/*/foo",
      true
    },
    { "http://en.google.com:8000/blah/*/foo",
      "http://en.google.com:8080/blah/*/foo",
      false
    },

    // paths
    { "http://en.google.com/blah/*/foo",
      "http://en.google.com/blah/*",
      false
    },
    { "http://en.google.com/*",
      "http://en.google.com/",
      false
    },
    { "http://en.google.com/*",
      "http://en.google.com/*",
      true
    },

    // all_urls
    { "<all_urls>",
      "<all_urls>",
      true
    },
    { "<all_urls>",
      "http://*/*",
      false
    }
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEqualsTestCases); ++i) {
    std::string message = kEqualsTestCases[i].pattern1;
    message += " ";
    message += kEqualsTestCases[i].pattern2;

    URLPattern pattern1(URLPattern::SCHEME_ALL);
    URLPattern pattern2(URLPattern::SCHEME_ALL);

    pattern1.Parse(kEqualsTestCases[i].pattern1);
    pattern2.Parse(kEqualsTestCases[i].pattern2);
    EXPECT_EQ(kEqualsTestCases[i].expected_equal, pattern1 == pattern2)
        << message;
  }
}

TEST(ExtensionURLPatternTest, CanReusePatternWithParse) {
  URLPattern pattern1(URLPattern::SCHEME_ALL);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse("http://aa.com/*"));
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse("http://bb.com/*"));

  EXPECT_TRUE(pattern1.MatchesURL(GURL("http://bb.com/path")));
  EXPECT_FALSE(pattern1.MatchesURL(GURL("http://aa.com/path")));

  URLPattern pattern2(URLPattern::SCHEME_ALL, URLPattern::kAllUrlsPattern);
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern2.Parse("http://aa.com/*"));

  EXPECT_FALSE(pattern2.MatchesURL(GURL("http://bb.com/path")));
  EXPECT_TRUE(pattern2.MatchesURL(GURL("http://aa.com/path")));
  EXPECT_FALSE(pattern2.MatchesURL(GURL("http://sub.aa.com/path")));

  URLPattern pattern3(URLPattern::SCHEME_ALL, "http://aa.com/*");
  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern3.Parse("http://aa.com:88/*"));
  EXPECT_FALSE(pattern3.MatchesURL(GURL("http://aa.com/path")));
  EXPECT_TRUE(pattern3.MatchesURL(GURL("http://aa.com:88/path")));
}

// Returns success if neither |a| nor |b| encompasses the other.
testing::AssertionResult NeitherContains(const URLPattern& a,
                                         const URLPattern& b) {
  if (a.Contains(b))
    return testing::AssertionFailure() << a.GetAsString() << " encompasses " <<
                                          b.GetAsString();
  if (b.Contains(a))
    return testing::AssertionFailure() << b.GetAsString() << " encompasses " <<
                                          a.GetAsString();
  return testing::AssertionSuccess() <<
      "Neither " << a.GetAsString() << " nor " << b.GetAsString() <<
      " encompass the other";
}

// Returns success if |a| encompasses |b| but not the other way around.
testing::AssertionResult StrictlyContains(const URLPattern& a,
                                          const URLPattern& b) {
  if (!a.Contains(b))
    return testing::AssertionFailure() << a.GetAsString() <<
                                          " does not encompass " <<
                                          b.GetAsString();
  if (b.Contains(a))
    return testing::AssertionFailure() << b.GetAsString() << " encompasses " <<
                                          a.GetAsString();
  return testing::AssertionSuccess() << a.GetAsString() <<
                                        " strictly encompasses " <<
                                        b.GetAsString();
}

TEST(ExtensionURLPatternTest, Subset) {
  URLPattern pattern1(kAllSchemes, "http://www.google.com/foo/*");
  URLPattern pattern2(kAllSchemes, "https://www.google.com/foo/*");
  URLPattern pattern3(kAllSchemes, "http://*.google.com/foo/*");
  URLPattern pattern4(kAllSchemes, "http://*.yahooo.com/foo/*");
  URLPattern pattern5(kAllSchemes, "http://www.yahooo.com/bar/*");
  URLPattern pattern6(kAllSchemes, "http://www.yahooo.com/bar/baz/*");
  URLPattern pattern7(kAllSchemes, "file:///*");
  URLPattern pattern8(kAllSchemes, "*://*/*");
  URLPattern pattern9(URLPattern::SCHEME_HTTPS, "*://*/*");
  URLPattern pattern10(kAllSchemes, "<all_urls>");
  URLPattern pattern11(kAllSchemes, "http://example.com/*");
  URLPattern pattern12(kAllSchemes, "*://example.com/*");
  URLPattern pattern13(kAllSchemes, "*://example.com/foo/*");

  // All patterns should encompass themselves.
  EXPECT_TRUE(pattern1.Contains(pattern1));
  EXPECT_TRUE(pattern2.Contains(pattern2));
  EXPECT_TRUE(pattern3.Contains(pattern3));
  EXPECT_TRUE(pattern4.Contains(pattern4));
  EXPECT_TRUE(pattern5.Contains(pattern5));
  EXPECT_TRUE(pattern6.Contains(pattern6));
  EXPECT_TRUE(pattern7.Contains(pattern7));
  EXPECT_TRUE(pattern8.Contains(pattern8));
  EXPECT_TRUE(pattern9.Contains(pattern9));
  EXPECT_TRUE(pattern10.Contains(pattern10));
  EXPECT_TRUE(pattern11.Contains(pattern11));
  EXPECT_TRUE(pattern12.Contains(pattern12));
  EXPECT_TRUE(pattern13.Contains(pattern13));

  // pattern1's relationship to the other patterns.
  EXPECT_TRUE(NeitherContains(pattern1, pattern2));
  EXPECT_TRUE(StrictlyContains(pattern3, pattern1));
  EXPECT_TRUE(NeitherContains(pattern1, pattern4));
  EXPECT_TRUE(NeitherContains(pattern1, pattern5));
  EXPECT_TRUE(NeitherContains(pattern1, pattern6));
  EXPECT_TRUE(NeitherContains(pattern1, pattern7));
  EXPECT_TRUE(StrictlyContains(pattern8, pattern1));
  EXPECT_TRUE(NeitherContains(pattern1, pattern9));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern1));
  EXPECT_TRUE(NeitherContains(pattern1, pattern11));
  EXPECT_TRUE(NeitherContains(pattern1, pattern12));
  EXPECT_TRUE(NeitherContains(pattern1, pattern13));

  // pattern2's relationship to the other patterns.
  EXPECT_TRUE(NeitherContains(pattern2, pattern3));
  EXPECT_TRUE(NeitherContains(pattern2, pattern4));
  EXPECT_TRUE(NeitherContains(pattern2, pattern5));
  EXPECT_TRUE(NeitherContains(pattern2, pattern6));
  EXPECT_TRUE(NeitherContains(pattern2, pattern7));
  EXPECT_TRUE(StrictlyContains(pattern8, pattern2));
  EXPECT_TRUE(StrictlyContains(pattern9, pattern2));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern2));
  EXPECT_TRUE(NeitherContains(pattern2, pattern11));
  EXPECT_TRUE(NeitherContains(pattern2, pattern12));
  EXPECT_TRUE(NeitherContains(pattern2, pattern13));

  // Specifically test file:// URLs.
  EXPECT_TRUE(NeitherContains(pattern7, pattern8));
  EXPECT_TRUE(NeitherContains(pattern7, pattern9));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern7));

  // <all_urls> encompasses everything.
  EXPECT_TRUE(StrictlyContains(pattern10, pattern1));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern2));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern3));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern4));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern5));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern6));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern7));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern8));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern9));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern11));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern12));
  EXPECT_TRUE(StrictlyContains(pattern10, pattern13));

  // More...
  EXPECT_TRUE(StrictlyContains(pattern12, pattern11));
  EXPECT_TRUE(NeitherContains(pattern11, pattern13));
  EXPECT_TRUE(StrictlyContains(pattern12, pattern13));
}

}  // namespace

/* [<][>][^][v][top][bottom][index][help] */