music on atproto
plyr.fm
1"""tests for OAuth scope validation functions."""
2
3from backend._internal.auth import (
4 _check_scope_coverage,
5 _get_missing_scopes,
6 _parse_scopes,
7)
8
9
10class TestParseScopes:
11 """tests for _parse_scopes."""
12
13 def test_parses_standard_scope_string(self):
14 """should extract repo: scopes from atproto scope string."""
15 scope = "atproto repo:fm.plyr.track repo:fm.plyr.like"
16 result = _parse_scopes(scope)
17 assert result == {"repo:fm.plyr.track", "repo:fm.plyr.like"}
18
19 def test_ignores_atproto_prefix(self):
20 """should not include 'atproto' in parsed scopes."""
21 scope = "atproto repo:fm.plyr.track"
22 result = _parse_scopes(scope)
23 assert "atproto" not in result
24 assert result == {"repo:fm.plyr.track"}
25
26 def test_handles_empty_string(self):
27 """should return empty set for empty scope."""
28 result = _parse_scopes("")
29 assert result == set()
30
31 def test_handles_multiple_scopes(self):
32 """should handle three or more scopes."""
33 scope = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment"
34 result = _parse_scopes(scope)
35 assert result == {
36 "repo:fm.plyr.track",
37 "repo:fm.plyr.like",
38 "repo:fm.plyr.comment",
39 }
40
41
42class TestCheckScopeCoverage:
43 """tests for _check_scope_coverage."""
44
45 def test_returns_true_when_all_scopes_granted(self):
46 """should return True when granted scope covers all required."""
47 granted = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment"
48 required = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment"
49 assert _check_scope_coverage(granted, required) is True
50
51 def test_returns_true_when_extra_scopes_granted(self):
52 """should return True when granted has more than required."""
53 granted = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment repo:fm.plyr.extra"
54 required = "atproto repo:fm.plyr.track repo:fm.plyr.like"
55 assert _check_scope_coverage(granted, required) is True
56
57 def test_returns_false_when_missing_scope(self):
58 """should return False when granted is missing required scope."""
59 granted = "atproto repo:fm.plyr.track repo:fm.plyr.like"
60 required = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment"
61 assert _check_scope_coverage(granted, required) is False
62
63 def test_returns_false_when_granted_empty(self):
64 """should return False when granted scope is empty."""
65 granted = ""
66 required = "atproto repo:fm.plyr.track"
67 assert _check_scope_coverage(granted, required) is False
68
69 def test_returns_true_when_both_empty(self):
70 """should return True when both are empty."""
71 assert _check_scope_coverage("", "") is True
72
73
74class TestGetMissingScopes:
75 """tests for _get_missing_scopes."""
76
77 def test_returns_empty_when_all_covered(self):
78 """should return empty set when all scopes are granted."""
79 granted = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment"
80 required = "atproto repo:fm.plyr.track repo:fm.plyr.like"
81 result = _get_missing_scopes(granted, required)
82 assert result == set()
83
84 def test_returns_missing_scope(self):
85 """should return the missing scope."""
86 granted = "atproto repo:fm.plyr.track repo:fm.plyr.like"
87 required = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment"
88 result = _get_missing_scopes(granted, required)
89 assert result == {"repo:fm.plyr.comment"}
90
91 def test_returns_multiple_missing_scopes(self):
92 """should return all missing scopes."""
93 granted = "atproto repo:fm.plyr.track"
94 required = "atproto repo:fm.plyr.track repo:fm.plyr.like repo:fm.plyr.comment"
95 result = _get_missing_scopes(granted, required)
96 assert result == {"repo:fm.plyr.like", "repo:fm.plyr.comment"}