Fix SchemeHostPort::GetURL() and add more tests

The implementation erroneously
 - Added an extra / to invalid URLs
 - Populated empty (len 0) url::Parsed components when they were empty in
   the class. Instead, they should have begin 0 and len -1.

BUG=651554

Review-Url: https://codereview.chromium.org/2387143003
Cr-Commit-Position: refs/heads/master@{#424059}
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index 9bb9b03..c692e6b 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -13,24 +13,26 @@
 
 namespace {
 
-void ExpectParsedComponentEqual(const url::Component& a,
-                                const url::Component& b) {
-  EXPECT_EQ(a.begin, b.begin);
-  EXPECT_EQ(a.len, b.len);
-}
-
 void ExpectParsedUrlsEqual(const GURL& a, const GURL& b) {
   EXPECT_EQ(a, b);
   const url::Parsed& a_parsed = a.parsed_for_possibly_invalid_spec();
   const url::Parsed& b_parsed = b.parsed_for_possibly_invalid_spec();
-  ExpectParsedComponentEqual(a_parsed.scheme, b_parsed.scheme);
-  ExpectParsedComponentEqual(a_parsed.username, b_parsed.username);
-  ExpectParsedComponentEqual(a_parsed.password, b_parsed.password);
-  ExpectParsedComponentEqual(a_parsed.host, b_parsed.host);
-  ExpectParsedComponentEqual(a_parsed.port, b_parsed.port);
-  ExpectParsedComponentEqual(a_parsed.path, b_parsed.path);
-  ExpectParsedComponentEqual(a_parsed.query, b_parsed.query);
-  ExpectParsedComponentEqual(a_parsed.ref, b_parsed.ref);
+  EXPECT_EQ(a_parsed.scheme.begin, b_parsed.scheme.begin);
+  EXPECT_EQ(a_parsed.scheme.len, b_parsed.scheme.len);
+  EXPECT_EQ(a_parsed.username.begin, b_parsed.username.begin);
+  EXPECT_EQ(a_parsed.username.len, b_parsed.username.len);
+  EXPECT_EQ(a_parsed.password.begin, b_parsed.password.begin);
+  EXPECT_EQ(a_parsed.password.len, b_parsed.password.len);
+  EXPECT_EQ(a_parsed.host.begin, b_parsed.host.begin);
+  EXPECT_EQ(a_parsed.host.len, b_parsed.host.len);
+  EXPECT_EQ(a_parsed.port.begin, b_parsed.port.begin);
+  EXPECT_EQ(a_parsed.port.len, b_parsed.port.len);
+  EXPECT_EQ(a_parsed.path.begin, b_parsed.path.begin);
+  EXPECT_EQ(a_parsed.path.len, b_parsed.path.len);
+  EXPECT_EQ(a_parsed.query.begin, b_parsed.query.begin);
+  EXPECT_EQ(a_parsed.query.len, b_parsed.query.len);
+  EXPECT_EQ(a_parsed.ref.begin, b_parsed.ref.begin);
+  EXPECT_EQ(a_parsed.ref.len, b_parsed.ref.len);
 }
 
 TEST(OriginTest, UniqueOriginComparison) {
diff --git a/url/scheme_host_port.cc b/url/scheme_host_port.cc
index b959986..48cae13 100644
--- a/url/scheme_host_port.cc
+++ b/url/scheme_host_port.cc
@@ -153,6 +153,9 @@
   url::Parsed parsed;
   std::string serialized = SerializeInternal(&parsed);
 
+  if (IsInvalid())
+    return GURL(std::move(serialized), parsed, false);
+
   // If the serialized string is passed to GURL for parsing, it will append an
   // empty path "/". Add that here. Note: per RFC 6454 we cannot do this for
   // normal Origin serialization.
@@ -177,13 +180,17 @@
   if (IsInvalid())
     return result;
 
-  parsed->scheme = Component(0, scheme_.length());
-  result.append(scheme_);
+  if (!scheme_.empty()) {
+    parsed->scheme = Component(0, scheme_.length());
+    result.append(scheme_);
+  }
 
   result.append(kStandardSchemeSeparator);
 
-  parsed->host = Component(result.length(), host_.length());
-  result.append(host_);
+  if (!host_.empty()) {
+    parsed->host = Component(result.length(), host_.length());
+    result.append(host_);
+  }
 
   if (port_ == 0)
     return result;
diff --git a/url/scheme_host_port_unittest.cc b/url/scheme_host_port_unittest.cc
index a2b594c..81d4371 100644
--- a/url/scheme_host_port_unittest.cc
+++ b/url/scheme_host_port_unittest.cc
@@ -12,6 +12,28 @@
 
 namespace {
 
+void ExpectParsedUrlsEqual(const GURL& a, const GURL& b) {
+  EXPECT_EQ(a, b);
+  const url::Parsed& a_parsed = a.parsed_for_possibly_invalid_spec();
+  const url::Parsed& b_parsed = b.parsed_for_possibly_invalid_spec();
+  EXPECT_EQ(a_parsed.scheme.begin, b_parsed.scheme.begin);
+  EXPECT_EQ(a_parsed.scheme.len, b_parsed.scheme.len);
+  EXPECT_EQ(a_parsed.username.begin, b_parsed.username.begin);
+  EXPECT_EQ(a_parsed.username.len, b_parsed.username.len);
+  EXPECT_EQ(a_parsed.password.begin, b_parsed.password.begin);
+  EXPECT_EQ(a_parsed.password.len, b_parsed.password.len);
+  EXPECT_EQ(a_parsed.host.begin, b_parsed.host.begin);
+  EXPECT_EQ(a_parsed.host.len, b_parsed.host.len);
+  EXPECT_EQ(a_parsed.port.begin, b_parsed.port.begin);
+  EXPECT_EQ(a_parsed.port.len, b_parsed.port.len);
+  EXPECT_EQ(a_parsed.path.begin, b_parsed.path.begin);
+  EXPECT_EQ(a_parsed.path.len, b_parsed.path.len);
+  EXPECT_EQ(a_parsed.query.begin, b_parsed.query.begin);
+  EXPECT_EQ(a_parsed.query.len, b_parsed.query.len);
+  EXPECT_EQ(a_parsed.ref.begin, b_parsed.ref.begin);
+  EXPECT_EQ(a_parsed.ref.len, b_parsed.ref.len);
+}
+
 TEST(SchemeHostPortTest, Invalid) {
   url::SchemeHostPort invalid;
   EXPECT_EQ("", invalid.scheme());
@@ -37,6 +59,7 @@
     EXPECT_TRUE(tuple.Equals(tuple));
     EXPECT_TRUE(tuple.Equals(invalid));
     EXPECT_TRUE(invalid.Equals(tuple));
+    ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
   }
 }
 
@@ -63,6 +86,7 @@
     EXPECT_EQ(test.port, tuple.port());
     EXPECT_FALSE(tuple.IsInvalid());
     EXPECT_TRUE(tuple.Equals(tuple));
+    ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
   }
 }
 
@@ -98,6 +122,7 @@
     EXPECT_EQ(0, tuple.port());
     EXPECT_TRUE(tuple.IsInvalid());
     EXPECT_TRUE(tuple.Equals(tuple));
+    ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
   }
 }
 
@@ -125,6 +150,7 @@
     EXPECT_EQ("", tuple.host());
     EXPECT_EQ(0, tuple.port());
     EXPECT_TRUE(tuple.IsInvalid());
+    ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
   }
 }
 
@@ -160,6 +186,7 @@
     EXPECT_EQ(test.port, tuple.port());
     EXPECT_FALSE(tuple.IsInvalid());
     EXPECT_TRUE(tuple.Equals(tuple));
+    ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
   }
 }
 
@@ -184,6 +211,7 @@
     GURL url(test.url);
     url::SchemeHostPort tuple(url);
     EXPECT_EQ(test.expected, tuple.Serialize());
+    ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
   }
 }