@quenty/permissionprovider 14.43.0 → 14.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,203 @@
1
+ --!strict
2
+ --[[
3
+ Coverage for PermissionService's ServiceBag-driven lifecycle and permission queries, with a
4
+ single-user (creator) provider config and PlayerMock players.
5
+
6
+ The deny cases assume RunService:IsStudio() == false (true in the cloud test runner); in Studio
7
+ the service short-circuits every permission query to true.
8
+
9
+ @class PermissionService.spec.lua
10
+ ]]
11
+
12
+ local require = require(script.Parent.loader).load(script)
13
+
14
+ local Jest = require("Jest")
15
+ local Maid = require("Maid")
16
+ local PermissionLevel = require("PermissionLevel")
17
+ local PermissionProviderUtils = require("PermissionProviderUtils")
18
+ local PermissionService = require("PermissionService")
19
+ local PlayerMock = require("PlayerMock")
20
+ local PromiseTestUtils = require("PromiseTestUtils")
21
+ local ServiceBag = require("ServiceBag")
22
+
23
+ local describe = Jest.Globals.describe
24
+ local expect = Jest.Globals.expect
25
+ local it = Jest.Globals.it
26
+
27
+ local CREATOR_USER_ID = 12345
28
+
29
+ local remoteNameCounter = 0
30
+
31
+ local function setup()
32
+ local maid = Maid.new()
33
+ local serviceBag = maid:Add(ServiceBag.new())
34
+ local permissionService: PermissionService.PermissionService = serviceBag:GetService(PermissionService) :: any
35
+ serviceBag:Init()
36
+
37
+ -- Unique remote function name so services from separate tests never share the global remote.
38
+ remoteNameCounter += 1
39
+ local remoteFunctionName = string.format("PermissionServiceSpecRemote%d", remoteNameCounter)
40
+
41
+ return {
42
+ serviceBag = serviceBag,
43
+ permissionService = permissionService,
44
+ singleUserConfig = function(userId: number)
45
+ return PermissionProviderUtils.createSingleUserConfig({
46
+ userId = userId,
47
+ remoteFunctionName = remoteFunctionName,
48
+ })
49
+ end,
50
+ fakePlayer = function(userId: number): Player
51
+ return maid:Add(PlayerMock.new({ UserId = userId }))
52
+ end,
53
+ awaitBool = function(promise: any): boolean
54
+ expect(PromiseTestUtils.awaitSettled(promise, 5)).toEqual(true)
55
+ local ok, value = promise:Yield()
56
+ expect(ok).toEqual(true)
57
+ return value
58
+ end,
59
+ destroy = function(_self)
60
+ maid:DoCleaning()
61
+ end,
62
+ }
63
+ end
64
+
65
+ describe("PermissionService initialization", function()
66
+ it("should initialize and start with a configured provider", function()
67
+ local controller = setup()
68
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
69
+
70
+ expect(function()
71
+ controller.serviceBag:Start()
72
+ end).never.toThrow()
73
+
74
+ controller:destroy()
75
+ end)
76
+
77
+ it("should start with a provider derived from the game when none is configured", function()
78
+ local controller = setup()
79
+
80
+ expect(function()
81
+ controller.serviceBag:Start()
82
+ end).never.toThrow()
83
+
84
+ controller:destroy()
85
+ end)
86
+
87
+ it("should resolve the permission provider after start", function()
88
+ local controller = setup()
89
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
90
+
91
+ local promise = controller.permissionService:PromisePermissionProvider()
92
+ expect(promise:IsPending()).toEqual(true)
93
+
94
+ controller.serviceBag:Start()
95
+
96
+ expect(PromiseTestUtils.awaitSettled(promise, 5)).toEqual(true)
97
+ local ok, provider = promise:Yield()
98
+ expect(ok).toEqual(true)
99
+ expect((provider :: any).ClassName).toEqual("CreatorPermissionProvider")
100
+
101
+ controller:destroy()
102
+ end)
103
+ end)
104
+
105
+ describe("PermissionService.SetProviderFromConfig", function()
106
+ it("should reject a second provider config", function()
107
+ local controller = setup()
108
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
109
+
110
+ expect(function()
111
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
112
+ end).toThrow("Already have provider set")
113
+
114
+ controller:destroy()
115
+ end)
116
+
117
+ it("should reject an unknown config type", function()
118
+ local controller = setup()
119
+
120
+ expect(function()
121
+ controller.permissionService:SetProviderFromConfig({ type = "UnknownConfigType" } :: any)
122
+ end).toThrow("Bad provider")
123
+
124
+ controller:destroy()
125
+ end)
126
+ end)
127
+
128
+ describe("PermissionService permission queries", function()
129
+ it("should treat the configured user as an admin", function()
130
+ local controller = setup()
131
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
132
+ controller.serviceBag:Start()
133
+
134
+ local player = controller.fakePlayer(CREATOR_USER_ID)
135
+ expect(controller.awaitBool(controller.permissionService:PromiseIsAdmin(player))).toEqual(true)
136
+
137
+ controller:destroy()
138
+ end)
139
+
140
+ it("should treat the configured user as a creator", function()
141
+ local controller = setup()
142
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
143
+ controller.serviceBag:Start()
144
+
145
+ local player = controller.fakePlayer(CREATOR_USER_ID)
146
+ expect(controller.awaitBool(controller.permissionService:PromiseIsCreator(player))).toEqual(true)
147
+
148
+ controller:destroy()
149
+ end)
150
+
151
+ it("should deny another user admin permission", function()
152
+ local controller = setup()
153
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
154
+ controller.serviceBag:Start()
155
+
156
+ local player = controller.fakePlayer(CREATOR_USER_ID + 1)
157
+ expect(controller.awaitBool(controller.permissionService:PromiseIsAdmin(player))).toEqual(false)
158
+
159
+ controller:destroy()
160
+ end)
161
+
162
+ it("should reject a non-player value", function()
163
+ local controller = setup()
164
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
165
+ controller.serviceBag:Start()
166
+
167
+ expect(function()
168
+ controller.permissionService:PromiseIsAdmin(nil :: any)
169
+ end).toThrow("bad player")
170
+
171
+ controller:destroy()
172
+ end)
173
+
174
+ it("should reject an invalid permission level", function()
175
+ local controller = setup()
176
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
177
+ controller.serviceBag:Start()
178
+
179
+ local player = controller.fakePlayer(CREATOR_USER_ID)
180
+ expect(function()
181
+ controller.permissionService:PromiseIsPermissionLevel(player, "not-a-level" :: any)
182
+ end).toThrow("Bad permissionLevel")
183
+
184
+ controller:destroy()
185
+ end)
186
+ end)
187
+
188
+ describe("PermissionService.ObservePermissionedPlayersBrio", function()
189
+ it("should subscribe and unsubscribe without error on an empty server", function()
190
+ local controller = setup()
191
+ controller.permissionService:SetProviderFromConfig(controller.singleUserConfig(CREATOR_USER_ID))
192
+ controller.serviceBag:Start()
193
+
194
+ expect(function()
195
+ local subscription = controller.permissionService
196
+ :ObservePermissionedPlayersBrio(PermissionLevel.ADMIN)
197
+ :Subscribe(function() end)
198
+ subscription:Destroy()
199
+ end).never.toThrow()
200
+
201
+ controller:destroy()
202
+ end)
203
+ end)
@@ -11,6 +11,7 @@ local BaseObject = require("BaseObject")
11
11
  local GetRemoteFunction = require("GetRemoteFunction")
12
12
  local PermissionLevel = require("PermissionLevel")
13
13
  local PermissionProviderUtils = require("PermissionProviderUtils")
14
+ local PlayerMock = require("PlayerMock")
14
15
  local Promise = require("Promise")
15
16
  local Table = require("Table")
16
17
 
@@ -68,7 +69,7 @@ function BasePermissionProvider.PromiseIsPermissionLevel(
68
69
  player: Player,
69
70
  permissionLevel: PermissionLevel.PermissionLevel
70
71
  ): Promise.Promise<boolean>
71
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
72
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
72
73
  assert(PermissionLevel:IsValue(permissionLevel))
73
74
 
74
75
  error("Not implemented")
@@ -85,7 +86,7 @@ function BasePermissionProvider.IsPermissionLevel(
85
86
  player: Player,
86
87
  permissionLevel: PermissionLevel.PermissionLevel
87
88
  ): boolean
88
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
89
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
89
90
  assert(PermissionLevel:IsValue(permissionLevel))
90
91
 
91
92
  local promise = self:PromiseIsPermissionLevel(player, permissionLevel)
@@ -108,7 +109,7 @@ end
108
109
  @return Promise<boolean>
109
110
  ]=]
110
111
  function BasePermissionProvider.PromiseIsCreator(self: BasePermissionProvider, player: Player): Promise.Promise<boolean>
111
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
112
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
112
113
 
113
114
  return self:PromiseIsPermissionLevel(player, PermissionLevel.CREATOR)
114
115
  end
@@ -119,7 +120,7 @@ end
119
120
  @return Promise<boolean>
120
121
  ]=]
121
122
  function BasePermissionProvider.PromiseIsAdmin(self: BasePermissionProvider, player: Player): Promise.Promise<boolean>
122
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
123
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
123
124
 
124
125
  return self:PromiseIsPermissionLevel(player, PermissionLevel.ADMIN)
125
126
  end
@@ -135,7 +136,7 @@ end
135
136
  @return boolean
136
137
  ]=]
137
138
  function BasePermissionProvider.IsCreator(self: BasePermissionProvider, player: Player): boolean
138
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
139
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
139
140
 
140
141
  return self:IsPermissionLevel(player, PermissionLevel.CREATOR)
141
142
  end
@@ -151,7 +152,7 @@ end
151
152
  @return boolean
152
153
  ]=]
153
154
  function BasePermissionProvider.IsAdmin(self: BasePermissionProvider, player: Player): boolean
154
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
155
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
155
156
 
156
157
  return self:IsPermissionLevel(player, PermissionLevel.ADMIN)
157
158
  end
@@ -0,0 +1,136 @@
1
+ --!strict
2
+ --[[
3
+ @class BasePermissionProvider.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local BasePermissionProvider = require("BasePermissionProvider")
9
+ local Jest = require("Jest")
10
+ local Maid = require("Maid")
11
+ local PermissionLevel = require("PermissionLevel")
12
+ local PermissionProviderUtils = require("PermissionProviderUtils")
13
+ local PlayerMock = require("PlayerMock")
14
+ local Promise = require("Promise")
15
+
16
+ local describe = Jest.Globals.describe
17
+ local expect = Jest.Globals.expect
18
+ local it = Jest.Globals.it
19
+
20
+ local function createStubProvider(maid: Maid.Maid, promiseFactory: () -> any)
21
+ local StubPermissionProvider = setmetatable({}, BasePermissionProvider)
22
+ StubPermissionProvider.ClassName = "StubPermissionProvider"
23
+ StubPermissionProvider.__index = StubPermissionProvider
24
+
25
+ local queriedLevels = {}
26
+
27
+ function StubPermissionProvider.PromiseIsPermissionLevel(_self: any, _player: any, permissionLevel: any)
28
+ table.insert(queriedLevels, permissionLevel)
29
+ return promiseFactory()
30
+ end
31
+
32
+ local config = PermissionProviderUtils.createSingleUserConfig({ userId = 12345 })
33
+ local provider = maid:Add(setmetatable(BasePermissionProvider.new(config) :: any, StubPermissionProvider))
34
+
35
+ return provider, queriedLevels
36
+ end
37
+
38
+ describe("BasePermissionProvider.new", function()
39
+ it("should reject a nil config", function()
40
+ expect(function()
41
+ BasePermissionProvider.new(nil :: any)
42
+ end).toThrow("Bad config")
43
+ end)
44
+
45
+ it("should reject a config without a remote function name", function()
46
+ expect(function()
47
+ BasePermissionProvider.new({} :: any)
48
+ end).toThrow("remoteFunctionName")
49
+ end)
50
+ end)
51
+
52
+ describe("BasePermissionProvider.PromiseIsPermissionLevel", function()
53
+ it("should error as not implemented on the base class", function()
54
+ local maid = Maid.new()
55
+ local provider =
56
+ maid:Add(BasePermissionProvider.new(PermissionProviderUtils.createSingleUserConfig({ userId = 12345 })))
57
+ local player = maid:Add(PlayerMock.new({ UserId = 12345 }))
58
+
59
+ expect(function()
60
+ provider:PromiseIsPermissionLevel(player, PermissionLevel.ADMIN)
61
+ end).toThrow("Not implemented")
62
+
63
+ maid:DoCleaning()
64
+ end)
65
+
66
+ it("should reject a non-player value", function()
67
+ local maid = Maid.new()
68
+ local provider =
69
+ maid:Add(BasePermissionProvider.new(PermissionProviderUtils.createSingleUserConfig({ userId = 12345 })))
70
+
71
+ expect(function()
72
+ provider:PromiseIsPermissionLevel(nil :: any, PermissionLevel.ADMIN)
73
+ end).toThrow("Bad player")
74
+
75
+ maid:DoCleaning()
76
+ end)
77
+ end)
78
+
79
+ describe("BasePermissionProvider.IsPermissionLevel", function()
80
+ it("should return false while the underlying promise is pending", function()
81
+ local maid = Maid.new()
82
+ local provider = createStubProvider(maid, function()
83
+ return maid:Add(Promise.new())
84
+ end)
85
+ local player = maid:Add(PlayerMock.new({ UserId = 12345 }))
86
+
87
+ expect(provider:IsPermissionLevel(player, PermissionLevel.ADMIN)).toEqual(false)
88
+
89
+ maid:DoCleaning()
90
+ end)
91
+
92
+ it("should return the resolved value when the promise settles synchronously", function()
93
+ local maid = Maid.new()
94
+ local provider = createStubProvider(maid, function()
95
+ return Promise.resolved(true)
96
+ end)
97
+ local player = maid:Add(PlayerMock.new({ UserId = 12345 }))
98
+
99
+ expect(provider:IsPermissionLevel(player, PermissionLevel.ADMIN)).toEqual(true)
100
+ expect(provider:IsCreator(player)).toEqual(true)
101
+ expect(provider:IsAdmin(player)).toEqual(true)
102
+
103
+ maid:DoCleaning()
104
+ end)
105
+
106
+ it("should return false when the underlying promise rejects", function()
107
+ local maid = Maid.new()
108
+ local provider = createStubProvider(maid, function()
109
+ local promise = Promise.rejected("simulated failure")
110
+ promise:Catch(function() end)
111
+ return promise
112
+ end)
113
+ local player = maid:Add(PlayerMock.new({ UserId = 12345 }))
114
+
115
+ expect(provider:IsPermissionLevel(player, PermissionLevel.ADMIN)).toEqual(false)
116
+
117
+ maid:DoCleaning()
118
+ end)
119
+ end)
120
+
121
+ describe("BasePermissionProvider promise wrappers", function()
122
+ it("should route PromiseIsAdmin and PromiseIsCreator through the matching level", function()
123
+ local maid = Maid.new()
124
+ local provider, queriedLevels = createStubProvider(maid, function()
125
+ return Promise.resolved(true)
126
+ end)
127
+ local player = maid:Add(PlayerMock.new({ UserId = 12345 }))
128
+
129
+ provider:PromiseIsAdmin(player)
130
+ provider:PromiseIsCreator(player)
131
+
132
+ expect(queriedLevels).toEqual({ PermissionLevel.ADMIN, PermissionLevel.CREATOR } :: { string })
133
+
134
+ maid:DoCleaning()
135
+ end)
136
+ end)
@@ -14,6 +14,7 @@ local BasePermissionProvider = require("BasePermissionProvider")
14
14
  local PermissionLevel = require("PermissionLevel")
15
15
  local PermissionProviderConstants = require("PermissionProviderConstants")
16
16
  local PermissionProviderUtils = require("PermissionProviderUtils")
17
+ local PlayerMock = require("PlayerMock")
17
18
  local Promise = require("Promise")
18
19
 
19
20
  local CreatorPermissionProvider = setmetatable({}, BasePermissionProvider)
@@ -56,11 +57,14 @@ function CreatorPermissionProvider.PromiseIsPermissionLevel(
56
57
  player: Player,
57
58
  permissionLevel: PermissionLevel.PermissionLevel
58
59
  ): Promise.Promise<boolean>
59
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
60
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
60
61
  assert(PermissionLevel:IsValue(permissionLevel))
61
62
 
62
63
  if permissionLevel == PermissionLevel.ADMIN or permissionLevel == PermissionLevel.CREATOR then
63
- return Promise.resolved(player.UserId == self._userId or RunService:IsStudio())
64
+ return Promise.resolved(
65
+ (if PlayerMock.isMock(player) then PlayerMock.read(player, "UserId") else player.UserId) == self._userId
66
+ or RunService:IsStudio()
67
+ )
64
68
  else
65
69
  error("Unknown permissionLevel")
66
70
  end
@@ -0,0 +1,130 @@
1
+ --!strict
2
+ --[[
3
+ Coverage for CreatorPermissionProvider: a single configured userId is both admin and creator,
4
+ everyone else is neither. Players are stood in by PlayerMock, whose seeded UserId the provider
5
+ reads through PlayerMock.read.
6
+
7
+ The negative cases assume RunService:IsStudio() == false (true in the cloud test runner); in
8
+ Studio the provider grants everyone permission.
9
+
10
+ @class CreatorPermissionProvider.spec.lua
11
+ ]]
12
+
13
+ local require = require(script.Parent.loader).load(script)
14
+
15
+ local CreatorPermissionProvider = require("CreatorPermissionProvider")
16
+ local Jest = require("Jest")
17
+ local Maid = require("Maid")
18
+ local PermissionLevel = require("PermissionLevel")
19
+ local PermissionProviderUtils = require("PermissionProviderUtils")
20
+ local PlayerMock = require("PlayerMock")
21
+ local PromiseTestUtils = require("PromiseTestUtils")
22
+
23
+ local describe = Jest.Globals.describe
24
+ local expect = Jest.Globals.expect
25
+ local it = Jest.Globals.it
26
+
27
+ local CREATOR_USER_ID = 12345
28
+
29
+ local function setup()
30
+ local maid = Maid.new()
31
+ local provider = maid:Add(CreatorPermissionProvider.new(PermissionProviderUtils.createSingleUserConfig({
32
+ userId = CREATOR_USER_ID,
33
+ })))
34
+
35
+ return {
36
+ provider = provider,
37
+ fakePlayer = function(userId: number): Player
38
+ return maid:Add(PlayerMock.new({ UserId = userId }))
39
+ end,
40
+ awaitBool = function(promise: any): boolean
41
+ expect(PromiseTestUtils.awaitSettled(promise, 5)).toEqual(true)
42
+ local ok, value = promise:Yield()
43
+ expect(ok).toEqual(true)
44
+ return value
45
+ end,
46
+ destroy = function(_self)
47
+ maid:DoCleaning()
48
+ end,
49
+ }
50
+ end
51
+
52
+ describe("CreatorPermissionProvider.new", function()
53
+ it("should reject a group rank config", function()
54
+ expect(function()
55
+ CreatorPermissionProvider.new(PermissionProviderUtils.createGroupRankConfig({
56
+ groupId = 12345,
57
+ minAdminRequiredRank = 250,
58
+ minCreatorRequiredRank = 254,
59
+ }) :: any)
60
+ end).toThrow("Bad configType")
61
+ end)
62
+ end)
63
+
64
+ describe("CreatorPermissionProvider.PromiseIsPermissionLevel", function()
65
+ it("should treat the configured user as an admin", function()
66
+ local controller = setup()
67
+ local player = controller.fakePlayer(CREATOR_USER_ID)
68
+
69
+ expect(controller.awaitBool(controller.provider:PromiseIsAdmin(player))).toEqual(true)
70
+
71
+ controller:destroy()
72
+ end)
73
+
74
+ it("should treat the configured user as a creator", function()
75
+ local controller = setup()
76
+ local player = controller.fakePlayer(CREATOR_USER_ID)
77
+
78
+ expect(controller.awaitBool(controller.provider:PromiseIsCreator(player))).toEqual(true)
79
+
80
+ controller:destroy()
81
+ end)
82
+
83
+ it("should deny another user admin permission", function()
84
+ local controller = setup()
85
+ local player = controller.fakePlayer(CREATOR_USER_ID + 1)
86
+
87
+ expect(controller.awaitBool(controller.provider:PromiseIsAdmin(player))).toEqual(false)
88
+
89
+ controller:destroy()
90
+ end)
91
+
92
+ it("should deny another user creator permission", function()
93
+ local controller = setup()
94
+ local player = controller.fakePlayer(CREATOR_USER_ID + 1)
95
+
96
+ expect(controller.awaitBool(controller.provider:PromiseIsCreator(player))).toEqual(false)
97
+
98
+ controller:destroy()
99
+ end)
100
+
101
+ it("should resolve synchronously for the IsAdmin wrapper", function()
102
+ local controller = setup()
103
+ local player = controller.fakePlayer(CREATOR_USER_ID)
104
+
105
+ expect(controller.provider:IsAdmin(player)).toEqual(true)
106
+
107
+ controller:destroy()
108
+ end)
109
+
110
+ it("should reject a non-player value", function()
111
+ local controller = setup()
112
+
113
+ expect(function()
114
+ controller.provider:PromiseIsPermissionLevel(nil :: any, PermissionLevel.ADMIN)
115
+ end).toThrow("Bad player")
116
+
117
+ controller:destroy()
118
+ end)
119
+
120
+ it("should reject an invalid permission level", function()
121
+ local controller = setup()
122
+ local player = controller.fakePlayer(CREATOR_USER_ID)
123
+
124
+ expect(function()
125
+ controller.provider:PromiseIsPermissionLevel(player, "not-a-level" :: any)
126
+ end).toThrow()
127
+
128
+ controller:destroy()
129
+ end)
130
+ end)
@@ -15,6 +15,7 @@ local GroupUtils = require("GroupUtils")
15
15
  local PermissionLevel = require("PermissionLevel")
16
16
  local PermissionProviderConstants = require("PermissionProviderConstants")
17
17
  local PermissionProviderUtils = require("PermissionProviderUtils")
18
+ local PlayerMock = require("PlayerMock")
18
19
  local Promise = require("Promise")
19
20
 
20
21
  local GroupPermissionProvider = setmetatable({}, BasePermissionProvider)
@@ -62,7 +63,7 @@ function GroupPermissionProvider.Start(self: GroupPermissionProvider)
62
63
  getmetatable(GroupPermissionProvider).Start(self)
63
64
 
64
65
  self._maid:GiveTask(Players.PlayerRemoving:Connect(function(player: Player)
65
- local userId = player.UserId
66
+ local userId = if PlayerMock.isMock(player) then PlayerMock.read(player, "UserId") else player.UserId
66
67
 
67
68
  self._adminsCache[userId] = nil
68
69
  self._creatorCache[userId] = nil
@@ -97,7 +98,7 @@ function GroupPermissionProvider.PromiseIsPermissionLevel(
97
98
  player: Player,
98
99
  permissionLevel: PermissionLevel.PermissionLevel
99
100
  ): Promise.Promise<boolean>
100
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
101
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
101
102
  assert(PermissionLevel:IsValue(permissionLevel))
102
103
 
103
104
  if permissionLevel == PermissionLevel.ADMIN then
@@ -113,10 +114,11 @@ function GroupPermissionProvider._promiseIsCreator(
113
114
  self: GroupPermissionProvider,
114
115
  player: Player
115
116
  ): Promise.Promise<boolean>
116
- assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
117
+ assert((typeof(player) == "Instance" and player:IsA("Player")) or PlayerMock.isMock(player), "Bad player")
117
118
  assert(player:IsDescendantOf(game), "Bad player")
118
119
 
119
- if self._creatorCache[player.UserId] then
120
+ local userId = if PlayerMock.isMock(player) then PlayerMock.read(player, "UserId") else player.UserId
121
+ if self._creatorCache[userId] then
120
122
  return Promise.resolved(true)
121
123
  end
122
124
 
@@ -131,12 +133,13 @@ function GroupPermissionProvider._promiseIsAdmin(
131
133
  ): Promise.Promise<boolean>
132
134
  assert(player:IsDescendantOf(game))
133
135
 
136
+ local userId = if PlayerMock.isMock(player) then PlayerMock.read(player, "UserId") else player.UserId
134
137
  -- really not saving much time.
135
- if self._creatorCache[player.UserId] then
138
+ if self._creatorCache[userId] then
136
139
  return Promise.resolved(true)
137
140
  end
138
141
 
139
- if self._adminsCache[player.UserId] then
142
+ if self._adminsCache[userId] then
140
143
  return Promise.resolved(true)
141
144
  end
142
145
 
@@ -148,13 +151,14 @@ end
148
151
  function GroupPermissionProvider._handlePlayer(self: GroupPermissionProvider, player: Player): ()
149
152
  assert(player, "Bad player")
150
153
 
154
+ local userId = if PlayerMock.isMock(player) then PlayerMock.read(player, "UserId") else player.UserId
151
155
  self:_promiseRankInGroup(player):Then(function(rank)
152
156
  if rank >= self._config.minAdminRequiredRank then
153
- self._adminsCache[player.UserId] = true
157
+ self._adminsCache[userId] = true
154
158
  end
155
159
 
156
160
  if rank >= self._config.minCreatorRequiredRank then
157
- self._creatorCache[player.UserId] = true
161
+ self._creatorCache[userId] = true
158
162
  end
159
163
  end)
160
164
  end
@@ -165,12 +169,13 @@ function GroupPermissionProvider._promiseRankInGroup(
165
169
  ): Promise.Promise<number>
166
170
  assert(typeof(player) == "Instance", "Bad player")
167
171
 
168
- if self._promiseRankPromisesCache[player.UserId] then
169
- return self._promiseRankPromisesCache[player.UserId]
172
+ local userId = if PlayerMock.isMock(player) then PlayerMock.read(player, "UserId") else player.UserId
173
+ if self._promiseRankPromisesCache[userId] then
174
+ return self._promiseRankPromisesCache[userId]
170
175
  end
171
176
 
172
- self._promiseRankPromisesCache[player.UserId] = GroupUtils.promiseRankInGroup(player, self._config.groupId)
173
- return self._promiseRankPromisesCache[player.UserId]
177
+ self._promiseRankPromisesCache[userId] = GroupUtils.promiseRankInGroup(player, self._config.groupId)
178
+ return self._promiseRankPromisesCache[userId]
174
179
  end
175
180
 
176
181
  return GroupPermissionProvider