package permission import "testing" func TestHasRole(t *testing.T) { tests := []struct { groups []string role Role want bool }{ {[]string{"role:admin"}, RoleAdmin, true}, {[]string{"admin"}, RoleAdmin, true}, {[]string{"role:user"}, RoleAdmin, false}, {[]string{" role:service "}, RoleService, true}, } for _, tt := range tests { if got := HasRole(tt.groups, tt.role); got != tt.want { t.Fatalf("HasRole(%v, %q) = %v, want %v", tt.groups, tt.role, got, tt.want) } } } func TestHasPermissionHierarchy(t *testing.T) { groups := []string{"drive:write"} if !HasPermission(groups, ResourceDrive, LevelRead) { t.Fatal("write should satisfy read") } if !HasPermission(groups, ResourceDrive, LevelWrite) { t.Fatal("write should satisfy write") } if HasPermission(groups, ResourceDrive, LevelAdmin) { t.Fatal("write should not satisfy admin") } } func TestHasPermissionAdminBypass(t *testing.T) { groups := []string{"role:admin"} if !HasPermission(groups, ResourcePhotos, LevelAdmin) { t.Fatal("platform admin should bypass resource checks") } } func TestHasPermissionResourceAdmin(t *testing.T) { groups := []string{"calendar:admin"} if !HasPermission(groups, ResourceCalendar, LevelRead) { t.Fatal("resource admin should satisfy read") } if !HasPermission(groups, ResourceCalendar, LevelWrite) { t.Fatal("resource admin should satisfy write") } if !HasPermission(groups, ResourceCalendar, LevelAdmin) { t.Fatal("resource admin should satisfy admin") } } func TestWithSuiteDefaultsEmptyGroups(t *testing.T) { groups := WithSuiteDefaults(nil) if !HasRole(groups, RoleUser) { t.Fatal("expected role:user") } if !HasPermission(groups, ResourceContacts, LevelWrite) { t.Fatal("expected contacts write") } if !HasPermission(groups, ResourceCalendar, LevelWrite) { t.Fatal("expected calendar write") } } func TestWithSuiteDefaultsPreservesExplicitResource(t *testing.T) { groups := WithSuiteDefaults([]string{"contacts:read"}) if !HasPermission(groups, ResourceContacts, LevelRead) { t.Fatal("expected contacts read") } if HasPermission(groups, ResourceContacts, LevelWrite) { t.Fatal("contacts:read must not be upgraded to write") } if HasPermission(groups, ResourceDrive, LevelRead) { t.Fatal("must not grant drive when contacts-only group is present") } } func TestDeriveAccountRole(t *testing.T) { if got := DeriveAccountRole(true, "active"); got != AccountRoleAdmin { t.Fatalf("admin = %q", got) } if got := DeriveAccountRole(false, "active"); got != AccountRoleUser { t.Fatalf("user = %q", got) } if got := DeriveAccountRole(false, "invited"); got != AccountRoleGuest { t.Fatalf("guest = %q", got) } if got := DeriveAccountRole(true, "disabled"); got != AccountRoleSuspended { t.Fatalf("suspended = %q", got) } } func TestWithGuestAccess(t *testing.T) { groups := WithGuestAccess(nil) if !HasRole(groups, RoleGuest) { t.Fatal("expected guest role") } if !HasPermission(groups, ResourceDrive, LevelWrite) { t.Fatal("expected drive write for own uploads") } if HasPermission(groups, ResourceContacts, LevelRead) { t.Fatal("guest must not get contacts") } if HasPermission(groups, ResourcePhotos, LevelRead) { t.Fatal("guest must not get photos") } } func TestWithSuiteDefaultsUserRoleOnly(t *testing.T) { groups := WithSuiteDefaults([]string{"role:user"}) if !HasPermission(groups, ResourceContacts, LevelWrite) { t.Fatal("role:user without resource groups should get suite defaults") } } func TestHasPermissionIsolation(t *testing.T) { groups := []string{"contacts:read"} if !HasPermission(groups, ResourceContacts, LevelRead) { t.Fatal("expected contacts read") } if HasPermission(groups, ResourceDrive, LevelRead) { t.Fatal("contacts permission must not grant drive access") } } func TestAdminScopeString(t *testing.T) { tests := []struct { scope AdminScope want string }{ {AdminScopeRead, "read"}, {AdminScopeWrite, "write"}, {AdminScope(0), "unknown"}, } for _, tt := range tests { if got := tt.scope.String(); got != tt.want { t.Fatalf("AdminScope(%d).String() = %q, want %q", tt.scope, got, tt.want) } } } func TestParseAdminScope(t *testing.T) { tests := []struct { in string want AdminScope ok bool }{ {"read", AdminScopeRead, true}, {"write", AdminScopeWrite, true}, {" READ ", AdminScopeRead, true}, {"Write", AdminScopeWrite, true}, {"admin", 0, false}, {"", 0, false}, } for _, tt := range tests { got, ok := ParseAdminScope(tt.in) if ok != tt.ok || got != tt.want { t.Fatalf("ParseAdminScope(%q) = (%v, %v), want (%v, %v)", tt.in, got, ok, tt.want, tt.ok) } } } func TestHasAdminScopeReadOnly(t *testing.T) { groups := []string{GroupAdminRead} if !HasAdminScope(groups, AdminScopeRead) { t.Fatal("admin:read should satisfy read scope") } if HasAdminScope(groups, AdminScopeWrite) { t.Fatal("admin:read should not satisfy write scope") } } func TestHasAdminScopeWriteImpliesRead(t *testing.T) { groups := []string{GroupAdminWrite} if !HasAdminScope(groups, AdminScopeRead) { t.Fatal("admin:write should satisfy read scope") } if !HasAdminScope(groups, AdminScopeWrite) { t.Fatal("admin:write should satisfy write scope") } } func TestHasAdminScopePlatformAdminBypass(t *testing.T) { tests := []struct { name string groups []string }{ {"bare admin role", []string{"admin"}}, {"prefixed admin role", []string{"role:admin"}}, {"trimmed prefixed admin role", []string{" role:admin "}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if !HasAdminScope(tt.groups, AdminScopeRead) { t.Fatal("platform admin should satisfy read scope") } if !HasAdminScope(tt.groups, AdminScopeWrite) { t.Fatal("platform admin should satisfy write scope") } if !HasAdminScope(tt.groups, DefaultAdminScope) { t.Fatal("platform admin should satisfy default admin scope") } }) } } func TestWithPlatformAdmin(t *testing.T) { groups := WithSuiteDefaults(nil) out := WithPlatformAdmin(groups) if !HasRole(out, RoleAdmin) { t.Fatal("expected admin role") } if !HasAdminScope(out, AdminScopeWrite) { t.Fatal("expected admin:write scope") } } func TestHasAdminScopeNoAccess(t *testing.T) { tests := []struct { name string groups []string }{ {"empty groups", nil}, {"unrelated user role", []string{"role:user"}}, {"resource permission only", []string{"drive:admin"}}, {"unknown admin suffix", []string{"admin:unknown"}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if HasAdminScope(tt.groups, AdminScopeRead) { t.Fatal("expected no admin read scope") } if HasAdminScope(tt.groups, AdminScopeWrite) { t.Fatal("expected no admin write scope") } }) } } func TestHasAdminScopeMaxWins(t *testing.T) { groups := []string{GroupAdminRead, GroupAdminWrite} if !HasAdminScope(groups, AdminScopeRead) { t.Fatal("combined scopes should satisfy read") } if !HasAdminScope(groups, AdminScopeWrite) { t.Fatal("combined scopes should satisfy write") } } func TestHasAdminScopeNormalization(t *testing.T) { groups := []string{" Admin:Write "} if !HasAdminScope(groups, AdminScopeWrite) { t.Fatal("admin scope groups should be case- and whitespace-normalized") } if !HasAdminScope(groups, AdminScopeRead) { t.Fatal("normalized admin:write should still imply read") } }