Auto-indexing service and GraphQL API for AT Protocol Records quickslice.slices.network/
atproto gleam graphql
at main 234 lines 5.6 kB view raw
1import gleam/option.{None, Some} 2import gleeunit/should 3import lib/oauth/scopes/parser 4import lib/oauth/scopes/types 5 6pub fn parse_atproto_test() { 7 parser.parse_scope("atproto") 8 |> should.be_ok 9 |> should.equal(types.Static(types.Atproto)) 10} 11 12pub fn parse_transition_generic_test() { 13 parser.parse_scope("transition:generic") 14 |> should.be_ok 15 |> should.equal(types.Static(types.TransitionGeneric)) 16} 17 18pub fn parse_transition_email_test() { 19 parser.parse_scope("transition:email") 20 |> should.be_ok 21 |> should.equal(types.Static(types.TransitionEmail)) 22} 23 24pub fn parse_transition_chat_bsky_test() { 25 parser.parse_scope("transition:chat.bsky") 26 |> should.be_ok 27 |> should.equal(types.Static(types.TransitionChatBsky)) 28} 29 30pub fn parse_account_email_test() { 31 parser.parse_scope("account:email") 32 |> should.be_ok 33 |> should.equal( 34 types.Account(types.AccountScope( 35 attribute: types.EmailAttr, 36 action: types.Read, 37 )), 38 ) 39} 40 41pub fn parse_account_email_with_action_test() { 42 parser.parse_scope("account:email?action=manage") 43 |> should.be_ok 44 |> should.equal( 45 types.Account(types.AccountScope( 46 attribute: types.EmailAttr, 47 action: types.Manage, 48 )), 49 ) 50} 51 52pub fn parse_account_repo_test() { 53 parser.parse_scope("account:repo") 54 |> should.be_ok 55 |> should.equal( 56 types.Account(types.AccountScope( 57 attribute: types.RepoAttr, 58 action: types.Read, 59 )), 60 ) 61} 62 63pub fn parse_account_status_test() { 64 parser.parse_scope("account:status?action=manage") 65 |> should.be_ok 66 |> should.equal( 67 types.Account(types.AccountScope( 68 attribute: types.StatusAttr, 69 action: types.Manage, 70 )), 71 ) 72} 73 74pub fn parse_identity_handle_test() { 75 parser.parse_scope("identity:handle") 76 |> should.be_ok 77 |> should.equal(types.Identity(types.IdentityScope(attribute: types.Handle))) 78} 79 80pub fn parse_identity_all_test() { 81 parser.parse_scope("identity:*") 82 |> should.be_ok 83 |> should.equal(types.Identity(types.IdentityScope(attribute: types.All))) 84} 85 86pub fn parse_repo_wildcard_test() { 87 parser.parse_scope("repo:*") 88 |> should.be_ok 89 |> should.equal( 90 types.Repo( 91 types.RepoScope(collection: "*", actions: [ 92 types.Create, 93 types.Update, 94 types.Delete, 95 ]), 96 ), 97 ) 98} 99 100pub fn parse_repo_specific_collection_test() { 101 parser.parse_scope("repo:app.bsky.feed.post") 102 |> should.be_ok 103 |> should.equal( 104 types.Repo( 105 types.RepoScope(collection: "app.bsky.feed.post", actions: [ 106 types.Create, 107 types.Update, 108 types.Delete, 109 ]), 110 ), 111 ) 112} 113 114pub fn parse_repo_with_single_action_test() { 115 parser.parse_scope("repo:app.bsky.feed.post?action=create") 116 |> should.be_ok 117 |> should.equal( 118 types.Repo( 119 types.RepoScope(collection: "app.bsky.feed.post", actions: [types.Create]), 120 ), 121 ) 122} 123 124pub fn parse_repo_with_multiple_actions_test() { 125 parser.parse_scope("repo:*?action=create&action=delete") 126 |> should.be_ok 127 |> should.equal( 128 types.Repo( 129 types.RepoScope(collection: "*", actions: [types.Create, types.Delete]), 130 ), 131 ) 132} 133 134pub fn parse_blob_wildcard_test() { 135 parser.parse_scope("blob:*/*") 136 |> should.be_ok 137 |> should.equal(types.Blob(types.BlobScope(mime_type: "*/*"))) 138} 139 140pub fn parse_blob_image_wildcard_test() { 141 parser.parse_scope("blob:image/*") 142 |> should.be_ok 143 |> should.equal(types.Blob(types.BlobScope(mime_type: "image/*"))) 144} 145 146pub fn parse_blob_specific_type_test() { 147 parser.parse_scope("blob:image/png") 148 |> should.be_ok 149 |> should.equal(types.Blob(types.BlobScope(mime_type: "image/png"))) 150} 151 152pub fn parse_blob_invalid_mime_test() { 153 parser.parse_scope("blob:invalid") 154 |> should.be_error 155} 156 157pub fn parse_rpc_specific_method_test() { 158 parser.parse_scope("rpc:app.bsky.feed.getFeed?aud=did:web:bsky.app") 159 |> should.be_ok 160 |> should.equal( 161 types.Rpc(types.RpcScope( 162 methods: ["app.bsky.feed.getFeed"], 163 audience: "did:web:bsky.app", 164 )), 165 ) 166} 167 168pub fn parse_rpc_wildcard_method_specific_aud_test() { 169 parser.parse_scope("rpc:*?aud=did:web:api.bsky.app") 170 |> should.be_ok 171 |> should.equal( 172 types.Rpc(types.RpcScope(methods: ["*"], audience: "did:web:api.bsky.app")), 173 ) 174} 175 176pub fn parse_rpc_missing_aud_test() { 177 parser.parse_scope("rpc:app.bsky.feed.getFeed") 178 |> should.be_error 179} 180 181pub fn parse_rpc_wildcard_both_test() { 182 // rpc:* with aud=* is invalid 183 parser.parse_scope("rpc:*?aud=*") 184 |> should.be_error 185} 186 187pub fn parse_include_simple_test() { 188 parser.parse_scope("include:app.bsky.feed") 189 |> should.be_ok 190 |> should.equal( 191 types.Include(types.IncludeScope(nsid: "app.bsky.feed", audience: None)), 192 ) 193} 194 195pub fn parse_include_with_aud_test() { 196 parser.parse_scope("include:chat.bsky.moderation?aud=did:web:bsky.chat") 197 |> should.be_ok 198 |> should.equal( 199 types.Include(types.IncludeScope( 200 nsid: "chat.bsky.moderation", 201 audience: Some("did:web:bsky.chat"), 202 )), 203 ) 204} 205 206pub fn parse_scopes_multiple_test() { 207 parser.parse_scopes("atproto repo:* account:email") 208 |> should.be_ok 209 |> should.equal([ 210 types.Static(types.Atproto), 211 types.Repo( 212 types.RepoScope(collection: "*", actions: [ 213 types.Create, 214 types.Update, 215 types.Delete, 216 ]), 217 ), 218 types.Account(types.AccountScope( 219 attribute: types.EmailAttr, 220 action: types.Read, 221 )), 222 ]) 223} 224 225pub fn parse_scopes_empty_test() { 226 parser.parse_scopes("") 227 |> should.be_ok 228 |> should.equal([]) 229} 230 231pub fn parse_scopes_single_invalid_fails_test() { 232 parser.parse_scopes("atproto invalid::: repo:*") 233 |> should.be_error 234}