Repository: pallets/werkzeug

Issue:
`Authorization` should support equality check
As shown in https://github.com/csernazs/pytest-httpserver/issues/241, it can be useful in tests to check if two `Authorization` or `WWWAuthenticate` objects are equal. Implement `__eq__` for both classes.


Discussion:

Resolving patch:
diff --git a/src/werkzeug/datastructures/auth.py b/src/werkzeug/datastructures/auth.py
--- a/src/werkzeug/datastructures/auth.py
+++ b/src/werkzeug/datastructures/auth.py
@@ -78,6 +78,16 @@ def get(self, key: str, default: str | None = None) -> str | None:
     def __contains__(self, key: str) -> bool:
         return key in self.parameters
 
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, Authorization):
+            return NotImplemented
+
+        return (
+            other.type == self.type
+            and other.token == self.token
+            and other.parameters == self.parameters
+        )
+
     @classmethod
     def from_header(cls, value: str | None) -> te.Self | None:
         """Parse an ``Authorization`` header value and return an instance, or ``None``
@@ -339,6 +349,16 @@ def __delattr__(self, name: str) -> None:
     def __contains__(self, key: str) -> bool:
         return key in self.parameters
 
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, WWWAuthenticate):
+            return NotImplemented
+
+        return (
+            other.type == self.type
+            and other.token == self.token
+            and other.parameters == self.parameters
+        )
+
     def get(self, key: str, default: str | None = None) -> str | None:
         return self.parameters.get(key, default)
 


Test patch:
diff --git a/tests/test_http.py b/tests/test_http.py
--- a/tests/test_http.py
+++ b/tests/test_http.py
@@ -208,6 +208,18 @@ def test_bad_authorization_header_encoding(self):
         content = base64.b64encode(b"\xffser:pass").decode()
         assert Authorization.from_header(f"Basic {content}") is None
 
+    def test_authorization_eq(self):
+        basic1 = Authorization.from_header("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")
+        basic2 = Authorization(
+            "basic", {"username": "Aladdin", "password": "open sesame"}
+        )
+        assert basic1 == basic2
+        bearer1 = Authorization.from_header("Bearer abc")
+        bearer2 = Authorization("bearer", token="abc")
+        assert bearer1 == bearer2
+        assert basic1 != bearer1
+        assert basic1 != object()
+
     def test_www_authenticate_header(self):
         wa = WWWAuthenticate.from_header('Basic realm="WallyWorld"')
         assert wa.type == "basic"
@@ -230,6 +242,16 @@ def test_www_authenticate_header(self):
         assert WWWAuthenticate.from_header("broken").type == "broken"
         assert WWWAuthenticate.from_header("") is None
 
+    def test_www_authenticate_eq(self):
+        basic1 = WWWAuthenticate.from_header("Basic realm=abc")
+        basic2 = WWWAuthenticate("basic", {"realm": "abc"})
+        assert basic1 == basic2
+        token1 = WWWAuthenticate.from_header("Token abc")
+        token2 = WWWAuthenticate("token", token="abc")
+        assert token1 == token2
+        assert basic1 != token1
+        assert basic1 != object()
+
     def test_etags(self):
         assert http.quote_etag("foo") == '"foo"'
         assert http.quote_etag("foo", True) == 'W/"foo"'