Commit 48344c9f862 for php.net

commit 48344c9f86239c7be1ab48754e1214917f687dcd
Author: Máté Kocsis <kocsismate@woohoolabs.com>
Date:   Tue Jan 13 22:45:58 2026 +0100

    Reorganize ext/uri tests - equivalence (#20391)

diff --git a/ext/uri/tests/036.phpt b/ext/uri/tests/036.phpt
deleted file mode 100644
index 2942730739d..00000000000
--- a/ext/uri/tests/036.phpt
+++ /dev/null
@@ -1,39 +0,0 @@
---TEST--
-Test URI equality checks
---EXTENSIONS--
-uri
---FILE--
-<?php
-
-var_dump(new Uri\Rfc3986\Uri("https://example.com")->equals(new Uri\Rfc3986\Uri("https://example.com"))); // true: identical URIs
-var_dump(new Uri\Rfc3986\Uri("https://example.com#foo")->equals(new Uri\Rfc3986\Uri("https://example.com#bar"), Uri\UriComparisonMode::ExcludeFragment)); // true: fragment differs, but fragment is excluded
-var_dump(new Uri\Rfc3986\Uri("https://example.com#foo")->equals(new Uri\Rfc3986\Uri("https://example.com#bar"), Uri\UriComparisonMode::IncludeFragment)); // false: fragment differs and fragment is included
-var_dump(new Uri\Rfc3986\Uri("https://example.com/foo/..")->equals(new Uri\Rfc3986\Uri("https://example.com"))); // false: first URI becomes https://example.com/ after normalization
-var_dump(new Uri\Rfc3986\Uri("https://example.com/foo/..")->equals(new Uri\Rfc3986\Uri("https://example.com/"))); // true: both URIs are https://example.com/ after normalization
-var_dump(new Uri\Rfc3986\Uri("http://example%2ecom/foo%2fb%61r")->equals(new Uri\Rfc3986\Uri("http://example%2ecom/foo/bar"))); // false: "/" in the path should not be decoded
-var_dump(new Uri\Rfc3986\Uri("http://example%2ecom/foo/b%61r")->equals(new Uri\Rfc3986\Uri("http://example%2ecom/foo/bar"))); // true: percent-decoding during normalization gives same URIs
-
-var_dump(new Uri\WhatWg\Url("https://example.com")->equals(new Uri\WhatWg\Url("https://example.com"))); // true: identical URIs
-var_dump(new Uri\WhatWg\Url("https://example.com#foo")->equals(new Uri\WhatWg\Url("https://example.com#bar"), Uri\UriComparisonMode::ExcludeFragment)); // true: fragment differs, but fragment is excluded
-var_dump(new Uri\WhatWg\Url("https://example.com#foo")->equals(new Uri\WhatWg\Url("https://example.com#bar"), Uri\UriComparisonMode::IncludeFragment)); // false: fragment differs and fragment is included
-var_dump(new Uri\WhatWg\Url("https://example.com/foo/..")->equals(new Uri\WhatWg\Url("https://example.com"))); // true: both URIs are https://example.com/ after normalization
-var_dump(new Uri\WhatWg\Url("https://example.com/foo/..")->equals(new Uri\WhatWg\Url("https://example.com/"))); // true: both URIs are https://example.com/ after normalization
-var_dump(new Uri\WhatWg\Url("http://example%2ecom/foo%2fb%61r")->equals(new Uri\WhatWg\Url("http://example%2ecom/foo/bar"))); // false: WHATWG doesn't percent-decode the path during normalization
-var_dump(new Uri\WhatWg\Url("http://example%2ecom/foo/b%61r")->equals(new Uri\WhatWg\Url("http://example.com/foo/b%61r"))); // true: WHATWG percent-decodes the host during normalization
-
-?>
---EXPECT--
-bool(true)
-bool(true)
-bool(false)
-bool(false)
-bool(true)
-bool(false)
-bool(true)
-bool(true)
-bool(true)
-bool(false)
-bool(true)
-bool(true)
-bool(false)
-bool(true)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_host.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_host.phpt
new file mode 100644
index 00000000000..b4e6cffcaf1
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_false_host.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns false - host is different
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user:info@192.168.0.1:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_path.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_path.phpt
new file mode 100644
index 00000000000..562719537f7
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_false_path.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns false - path is different
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar/baz?abc=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_port.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_port.phpt
new file mode 100644
index 00000000000..3743dd686a2
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_false_port.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns false - port is different
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:442/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_query.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_query.phpt
new file mode 100644
index 00000000000..cb4fbcd9d6d
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_false_query.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns false - query is different
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_query2.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_query2.phpt
new file mode 100644
index 00000000000..b97988d9ce3
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_false_query2.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns false - query differs in casing
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?ABC=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_scheme.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_scheme.phpt
new file mode 100644
index 00000000000..143fbff97ee
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_false_scheme.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns false - scheme is different
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("http://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_false_userinfo.phpt b/ext/uri/tests/rfc3986/equivalence/equals_false_userinfo.phpt
new file mode 100644
index 00000000000..1d965c01eee
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_false_userinfo.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns false - userinfo is different
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_fragment_different.phpt b/ext/uri/tests/rfc3986/equivalence/equals_fragment_different.phpt
new file mode 100644
index 00000000000..0219002fcb6
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_fragment_different.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - different fragment - include fragment variation
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hash");
+
+var_dump($uri1->equals($uri2, Uri\UriComparisonMode::IncludeFragment));
+var_dump($uri2->equals($uri1, Uri\UriComparisonMode::IncludeFragment));
+
+var_dump($uri1->equals($uri2, Uri\UriComparisonMode::ExcludeFragment));
+var_dump($uri2->equals($uri1, Uri\UriComparisonMode::ExcludeFragment));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_true_identical.phpt b/ext/uri/tests/rfc3986/equivalence/equals_true_identical.phpt
new file mode 100644
index 00000000000..dc2839e3b82
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_true_identical.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns true - identical URIs
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2, Uri\UriComparisonMode::IncludeFragment));
+var_dump($uri2->equals($uri1, Uri\UriComparisonMode::IncludeFragment));
+
+var_dump($uri1->equals($uri2, Uri\UriComparisonMode::ExcludeFragment));
+var_dump($uri2->equals($uri1, Uri\UriComparisonMode::ExcludeFragment));
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_true_normalization1.phpt b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization1.phpt
new file mode 100644
index 00000000000..063ee977c5d
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization1.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns true - after multiple normalization steps
+--FILE--
+<?php
+
+$uri1 = Uri\Rfc3986\Uri::parse("https://user:info@example%2ecom:443/foo/bar?abc=123&def=ghi#hashmark");
+$uri2 = Uri\Rfc3986\Uri::parse("HTTPS://user:info@EXAMPLE.COM:0443/../foo/b%61r?abc=123&def=ghi#hashmark");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/rfc3986/equivalence/equals_true_normalization2.phpt b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization2.phpt
new file mode 100644
index 00000000000..e9b4d647f4a
--- /dev/null
+++ b/ext/uri/tests/rfc3986/equivalence/equals_true_normalization2.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\Rfc3986\Uri equivalence - returns true - after IPv6 normalization
+--FILE--
+<?php
+
+$uri1 = new Uri\Rfc3986\Uri("https://[2001:0db8:0001:0000:0000:0ab9:C0A8:0102]");
+$uri2 = new Uri\Rfc3986\Uri("https://[2001:DB8:1::AB9:C0A8:102]");
+
+var_dump($uri1->equals($uri2));
+var_dump($uri2->equals($uri1));
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_host.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_host.phpt
new file mode 100644
index 00000000000..9bea45ce2b8
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_host.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - host is different
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:pass@192.168.0.1:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_password.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_password.phpt
new file mode 100644
index 00000000000..3ef38d9b2d8
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_password.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - password is different
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_path.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_path.phpt
new file mode 100644
index 00000000000..aed0639a3c3
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_path.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - path is different
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar/baz?abc=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_path_percent_encoded.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_path_percent_encoded.phpt
new file mode 100644
index 00000000000..03dfc43e02e
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_path_percent_encoded.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - path is not percent-decoded during normalization
+--FILE--
+<?php
+
+$url1 = new Uri\WhatWg\Url("https://example.com/foo/bar");
+$url2 = new Uri\WhatWg\Url("https://example.com/foo/b%61r");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_port.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_port.phpt
new file mode 100644
index 00000000000..f632cb403f6
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_port.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - port is different
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:pass@example.com:442/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_query.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_query.phpt
new file mode 100644
index 00000000000..befed30ae2b
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_query.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - query is different
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_query2.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_query2.phpt
new file mode 100644
index 00000000000..b155a1214df
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_query2.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - query differs in casing
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?ABC=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_false_user.phpt b/ext/uri/tests/whatwg/equivalence/equals_false_user.phpt
new file mode 100644
index 00000000000..c0f815fa936
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_false_user.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns false - user is different
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://usr:pass@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_fragment_different.phpt b/ext/uri/tests/whatwg/equivalence/equals_fragment_different.phpt
new file mode 100644
index 00000000000..daa6a7e8ea6
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_fragment_different.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - different fragment - include fragment variation
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hash");
+
+var_dump($url1->equals($url2, Uri\UriComparisonMode::IncludeFragment));
+var_dump($url2->equals($url1, Uri\UriComparisonMode::IncludeFragment));
+
+var_dump($url1->equals($url2, Uri\UriComparisonMode::ExcludeFragment));
+var_dump($url2->equals($url1, Uri\UriComparisonMode::ExcludeFragment));
+
+?>
+--EXPECT--
+bool(false)
+bool(false)
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_identical.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_identical.phpt
new file mode 100644
index 00000000000..4dffda8138c
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_true_identical.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns true - identical URIs
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("https://user:info@example.com:443/foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2, Uri\UriComparisonMode::IncludeFragment));
+var_dump($url2->equals($url1, Uri\UriComparisonMode::IncludeFragment));
+
+var_dump($url1->equals($url2, Uri\UriComparisonMode::ExcludeFragment));
+var_dump($url2->equals($url1, Uri\UriComparisonMode::ExcludeFragment));
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_normalization1.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_normalization1.phpt
new file mode 100644
index 00000000000..79736f760be
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_true_normalization1.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns true - after multiple normalization steps
+--FILE--
+<?php
+
+$url1 = Uri\WhatWg\Url::parse("https://user:info@example%2ecom:0443/foo/bar?abc=123&def=ghi#hashmark");
+$url2 = Uri\WhatWg\Url::parse("HTTPS://user:info@EXAMPLE.COM:443/../foo/bar?abc=123&def=ghi#hashmark");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_normalization2.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_normalization2.phpt
new file mode 100644
index 00000000000..2f5c767f975
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_true_normalization2.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns true - after IPv6 normalization
+--FILE--
+<?php
+
+$url1 = new Uri\WhatWg\Url("https://[2001:0db8:0001:0000:0000:0ab9:C0A8:0102]");
+$url2 = new Uri\WhatWg\Url("https://[2001:DB8:1::AB9:C0A8:102]");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(true)
+bool(true)
diff --git a/ext/uri/tests/whatwg/equivalence/equals_true_normalization3.phpt b/ext/uri/tests/whatwg/equivalence/equals_true_normalization3.phpt
new file mode 100644
index 00000000000..bbcf15512c4
--- /dev/null
+++ b/ext/uri/tests/whatwg/equivalence/equals_true_normalization3.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Test Uri\WhatWg\Url equivalence - returns true - after empty path normalization
+--FILE--
+<?php
+
+$url1 = new Uri\WhatWg\Url("https://example.com");
+$url2 = new Uri\WhatWg\Url("https://example.com/");
+
+var_dump($url1->equals($url2));
+var_dump($url2->equals($url1));
+
+?>
+--EXPECT--
+bool(true)
+bool(true)