@quenty/binder 14.40.0 → 14.41.0
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.
- package/CHANGELOG.md +6 -0
- package/package.json +13 -13
- package/src/Shared/Binder.Loading.spec.lua +54 -0
- package/src/Shared/Binder.ObserveBrio.spec.lua +209 -0
- package/src/Shared/Binder.spec.lua +120 -255
- package/src/Shared/BinderGroup.spec.lua +19 -24
- package/src/Shared/BinderTestUtils.lua +163 -0
- package/src/Shared/BinderUtils.spec.lua +94 -103
- package/src/Shared/Collection/BoundChildCollection.spec.lua +36 -45
- package/src/Shared/Promise/promiseBoundClass.spec.lua +21 -27
- package/src/Shared/Trackers/BoundAncestorTracker.spec.lua +36 -44
- package/src/Shared/Trackers/BoundParentTracker.spec.lua +28 -36
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--[[
|
|
3
|
-
Coverage for BinderGroup: grouping binders, optional constructor validation, and the
|
|
4
|
-
BinderAdded signal. The binders here are never started, so no CollectionService state is
|
|
5
|
-
touched; each is still destroyed through the setup() controller to avoid leaking into the
|
|
6
|
-
shared test place.
|
|
7
|
-
|
|
8
3
|
@class BinderGroup.spec.lua
|
|
9
4
|
]]
|
|
10
5
|
|
|
@@ -46,15 +41,15 @@ end
|
|
|
46
41
|
|
|
47
42
|
describe("BinderGroup.new()", function()
|
|
48
43
|
it("constructs with an initial list of binders", function()
|
|
49
|
-
local
|
|
44
|
+
local controller = setup()
|
|
50
45
|
|
|
51
|
-
local binderA =
|
|
52
|
-
local binderB =
|
|
46
|
+
local binderA = controller.newBinder()
|
|
47
|
+
local binderB = controller.newBinder()
|
|
53
48
|
local group = BinderGroup.new({ binderA, binderB })
|
|
54
49
|
|
|
55
50
|
expect(#group:GetBinders()).toEqual(2)
|
|
56
51
|
|
|
57
|
-
|
|
52
|
+
controller.destroy()
|
|
58
53
|
end)
|
|
59
54
|
|
|
60
55
|
it("constructs empty", function()
|
|
@@ -65,19 +60,19 @@ end)
|
|
|
65
60
|
|
|
66
61
|
describe("BinderGroup:Add()", function()
|
|
67
62
|
it("adds a binder and exposes it via GetBinders", function()
|
|
68
|
-
local
|
|
63
|
+
local controller = setup()
|
|
69
64
|
|
|
70
65
|
local group = BinderGroup.new({})
|
|
71
|
-
local binder =
|
|
66
|
+
local binder = controller.newBinder()
|
|
72
67
|
group:Add(binder)
|
|
73
68
|
|
|
74
69
|
expect(group:GetBinders()[1]).toEqual(binder)
|
|
75
70
|
|
|
76
|
-
|
|
71
|
+
controller.destroy()
|
|
77
72
|
end)
|
|
78
73
|
|
|
79
74
|
it("fires BinderAdded with the added binder", function()
|
|
80
|
-
local
|
|
75
|
+
local controller = setup()
|
|
81
76
|
|
|
82
77
|
local group = BinderGroup.new({})
|
|
83
78
|
local fired
|
|
@@ -85,12 +80,12 @@ describe("BinderGroup:Add()", function()
|
|
|
85
80
|
fired = binder
|
|
86
81
|
end)
|
|
87
82
|
|
|
88
|
-
local binder =
|
|
83
|
+
local binder = controller.newBinder()
|
|
89
84
|
group:Add(binder)
|
|
90
85
|
|
|
91
86
|
expect(fired).toEqual(binder)
|
|
92
87
|
|
|
93
|
-
|
|
88
|
+
controller.destroy()
|
|
94
89
|
end)
|
|
95
90
|
|
|
96
91
|
it("throws when the value is not a binder", function()
|
|
@@ -103,7 +98,7 @@ end)
|
|
|
103
98
|
|
|
104
99
|
describe("BinderGroup constructor validation", function()
|
|
105
100
|
it("accepts binders whose constructor passes validation", function()
|
|
106
|
-
local
|
|
101
|
+
local controller = setup()
|
|
107
102
|
|
|
108
103
|
local validated = {}
|
|
109
104
|
local group = BinderGroup.new({}, function(constructor)
|
|
@@ -111,40 +106,40 @@ describe("BinderGroup constructor validation", function()
|
|
|
111
106
|
return true
|
|
112
107
|
end)
|
|
113
108
|
|
|
114
|
-
local binder =
|
|
109
|
+
local binder = controller.newBinder()
|
|
115
110
|
group:Add(binder)
|
|
116
111
|
|
|
117
112
|
expect(validated[1]).toEqual(binder:GetConstructor())
|
|
118
113
|
|
|
119
|
-
|
|
114
|
+
controller.destroy()
|
|
120
115
|
end)
|
|
121
116
|
|
|
122
117
|
it("throws when the constructor fails validation", function()
|
|
123
|
-
local
|
|
118
|
+
local controller = setup()
|
|
124
119
|
|
|
125
120
|
local group = BinderGroup.new({}, function()
|
|
126
121
|
return false
|
|
127
122
|
end)
|
|
128
123
|
|
|
129
|
-
local binder =
|
|
124
|
+
local binder = controller.newBinder()
|
|
130
125
|
expect(function()
|
|
131
126
|
group:Add(binder)
|
|
132
127
|
end).toThrow()
|
|
133
128
|
|
|
134
|
-
|
|
129
|
+
controller.destroy()
|
|
135
130
|
end)
|
|
136
131
|
end)
|
|
137
132
|
|
|
138
133
|
describe("BinderGroup:AddList()", function()
|
|
139
134
|
it("adds each binder in the list", function()
|
|
140
|
-
local
|
|
135
|
+
local controller = setup()
|
|
141
136
|
|
|
142
137
|
local group = BinderGroup.new({})
|
|
143
|
-
group:AddList({
|
|
138
|
+
group:AddList({ controller.newBinder(), controller.newBinder() })
|
|
144
139
|
|
|
145
140
|
expect(#group:GetBinders()).toEqual(2)
|
|
146
141
|
|
|
147
|
-
|
|
142
|
+
controller.destroy()
|
|
148
143
|
end)
|
|
149
144
|
|
|
150
145
|
it("throws on a non-table argument", function()
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
--!nonstrict
|
|
2
|
+
--[=[
|
|
3
|
+
Shared harness for the Binder specs. [BinderTestUtils.setup] boots binders the way production code
|
|
4
|
+
boots them: registered on a [BinderProvider] that is Init/Start'd through a [ServiceBag] and torn
|
|
5
|
+
down through `serviceBag:Destroy()`. Adornees are parented into a workspace container because
|
|
6
|
+
CollectionService.GetInstanceAddedSignal only fires for instances that live in the DataModel.
|
|
7
|
+
|
|
8
|
+
Tags are global and the test place is shared across a batch run, so every binder gets a distinct
|
|
9
|
+
tag from a single module-level counter -- shared across every spec file that requires this module,
|
|
10
|
+
so tags never collide between files -- and each controller cleans up after itself via `destroy()`.
|
|
11
|
+
|
|
12
|
+
@class BinderTestUtils
|
|
13
|
+
]=]
|
|
14
|
+
|
|
15
|
+
local require = require(script.Parent.loader).load(script)
|
|
16
|
+
|
|
17
|
+
local Binder = require("Binder")
|
|
18
|
+
local BinderProvider = require("BinderProvider")
|
|
19
|
+
local ServiceBag = require("ServiceBag")
|
|
20
|
+
|
|
21
|
+
local BinderTestUtils = {}
|
|
22
|
+
|
|
23
|
+
local specCounter = 0
|
|
24
|
+
|
|
25
|
+
--[=[
|
|
26
|
+
A minimal bound class that records its instance and whether it was destroyed. It deliberately does
|
|
27
|
+
NOT retain its constructor varargs: the ServiceBag is injected as a constructor arg, and its object
|
|
28
|
+
graph contains Quenty Signals whose strict __index makes jest's deep-equality traversal throw.
|
|
29
|
+
Keeping the class free of them lets toEqual compare instances safely.
|
|
30
|
+
|
|
31
|
+
@return TrackingClass
|
|
32
|
+
]=]
|
|
33
|
+
function BinderTestUtils.makeTrackingClass()
|
|
34
|
+
local Class = {}
|
|
35
|
+
Class.__index = Class
|
|
36
|
+
Class.ClassName = "TrackingClass"
|
|
37
|
+
|
|
38
|
+
function Class.new(inst)
|
|
39
|
+
local self = setmetatable({}, Class)
|
|
40
|
+
self.instance = inst
|
|
41
|
+
self.destroyed = false
|
|
42
|
+
return self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
function Class:Destroy()
|
|
46
|
+
self.destroyed = true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
return Class
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
--[=[
|
|
53
|
+
Returns once `inst` is no longer bound. CollectionService tag removal is synchronous here, so the
|
|
54
|
+
class is usually already gone by the time we check; the guarded wait also covers a deferred case.
|
|
55
|
+
|
|
56
|
+
@param binder Binder
|
|
57
|
+
@param inst Instance
|
|
58
|
+
]=]
|
|
59
|
+
function BinderTestUtils.awaitUnbound(binder, inst)
|
|
60
|
+
if binder:Get(inst) ~= nil then
|
|
61
|
+
binder:GetClassRemovedSignal():Wait()
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
--[=[
|
|
66
|
+
A no-op constructor that still returns a value, so Binder's generic bound type stays inhabited.
|
|
67
|
+
|
|
68
|
+
@return table
|
|
69
|
+
]=]
|
|
70
|
+
function BinderTestUtils.noopConstructor()
|
|
71
|
+
return {}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
--[=[
|
|
75
|
+
Builds the controller the Binder specs share. Register binders with `addBinder`, boot them all at
|
|
76
|
+
once through a ServiceBag with `boot`, create adornees with `newInstance`, and tear everything down
|
|
77
|
+
with `destroy` (or just the service bag with `destroyServiceBag`).
|
|
78
|
+
|
|
79
|
+
Fields: `container`.
|
|
80
|
+
Builders: `addBinder(constructor, ...)` -> Binder, `newInstance(parent?, className?)` -> Instance.
|
|
81
|
+
Lifecycle: `boot()`, `destroyServiceBag()`, `destroy()`.
|
|
82
|
+
Helpers: `uniqueTag()` -> string.
|
|
83
|
+
|
|
84
|
+
@return { ... }
|
|
85
|
+
]=]
|
|
86
|
+
function BinderTestUtils.setup()
|
|
87
|
+
specCounter += 1
|
|
88
|
+
local suffix = specCounter
|
|
89
|
+
|
|
90
|
+
local serviceBag = ServiceBag.new()
|
|
91
|
+
local serviceBagDestroyed = false
|
|
92
|
+
|
|
93
|
+
local container = Instance.new("Folder")
|
|
94
|
+
container.Name = "BinderSpecContainer"
|
|
95
|
+
container.Parent = workspace
|
|
96
|
+
|
|
97
|
+
local instances = {}
|
|
98
|
+
local pendingBinders = {}
|
|
99
|
+
local extraTagCounter = 0
|
|
100
|
+
local booted = false
|
|
101
|
+
|
|
102
|
+
local function uniqueTag()
|
|
103
|
+
extraTagCounter += 1
|
|
104
|
+
return string.format("BinderSpecTag_%d_%d", suffix, extraTagCounter)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
local function addBinder(constructor, ...)
|
|
108
|
+
assert(not booted, "Cannot add a binder after boot()")
|
|
109
|
+
local binder = Binder.new(uniqueTag(), constructor, ...)
|
|
110
|
+
table.insert(pendingBinders, binder)
|
|
111
|
+
return binder
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
local function boot()
|
|
115
|
+
assert(not booted, "Already booted")
|
|
116
|
+
booted = true
|
|
117
|
+
|
|
118
|
+
local binders = pendingBinders
|
|
119
|
+
local provider = BinderProvider.new(string.format("BinderSpecProvider_%d", suffix), function(self)
|
|
120
|
+
for _, binder in binders do
|
|
121
|
+
self:Add(binder)
|
|
122
|
+
end
|
|
123
|
+
end)
|
|
124
|
+
|
|
125
|
+
serviceBag:GetService(provider)
|
|
126
|
+
serviceBag:Init()
|
|
127
|
+
serviceBag:Start()
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
local function newInstance(parent, className)
|
|
131
|
+
local inst = Instance.new(className or "Folder")
|
|
132
|
+
inst.Parent = parent or container
|
|
133
|
+
table.insert(instances, inst)
|
|
134
|
+
return inst
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
local function destroyServiceBag()
|
|
138
|
+
if not serviceBagDestroyed then
|
|
139
|
+
serviceBagDestroyed = true
|
|
140
|
+
serviceBag:Destroy()
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
container = container,
|
|
146
|
+
uniqueTag = uniqueTag,
|
|
147
|
+
addBinder = addBinder,
|
|
148
|
+
boot = boot,
|
|
149
|
+
newInstance = newInstance,
|
|
150
|
+
destroyServiceBag = destroyServiceBag,
|
|
151
|
+
destroy = function()
|
|
152
|
+
destroyServiceBag()
|
|
153
|
+
for _, inst in instances do
|
|
154
|
+
pcall(function()
|
|
155
|
+
inst:Destroy()
|
|
156
|
+
end)
|
|
157
|
+
end
|
|
158
|
+
container:Destroy()
|
|
159
|
+
end,
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
return BinderTestUtils
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
--[[
|
|
3
|
-
Coverage for BinderUtils lookup helpers.
|
|
4
|
-
|
|
5
|
-
Binders are booted through a ServiceBag (as production code does) and instances are tagged
|
|
6
|
-
BEFORE the service bag starts, so they bind synchronously and :Get() resolves without waiting.
|
|
7
|
-
Instances live in a workspace container so the binders' added signals fire. Each test tears
|
|
8
|
-
down its service bag and instances because the test place is shared across a batch run.
|
|
9
|
-
|
|
10
3
|
@class BinderUtils.spec.lua
|
|
11
4
|
]]
|
|
12
5
|
|
|
@@ -64,8 +57,6 @@ local function setup()
|
|
|
64
57
|
return inst
|
|
65
58
|
end
|
|
66
59
|
|
|
67
|
-
-- Tags each instance with the binder, then boots everything through the service bag so the
|
|
68
|
-
-- instances bind synchronously.
|
|
69
60
|
local function boot()
|
|
70
61
|
assert(not booted, "Already booted")
|
|
71
62
|
booted = true
|
|
@@ -100,248 +91,248 @@ end
|
|
|
100
91
|
|
|
101
92
|
describe("BinderUtils.findFirstAncestor()", function()
|
|
102
93
|
it("returns the nearest bound ancestor, skipping the child itself", function()
|
|
103
|
-
local
|
|
94
|
+
local controller = setup()
|
|
104
95
|
|
|
105
|
-
local grandparent =
|
|
106
|
-
local parent =
|
|
107
|
-
local child =
|
|
96
|
+
local grandparent = controller.newInstance()
|
|
97
|
+
local parent = controller.newInstance(grandparent)
|
|
98
|
+
local child = controller.newInstance(parent)
|
|
108
99
|
|
|
109
|
-
local binder =
|
|
100
|
+
local binder = controller.newBinder()
|
|
110
101
|
binder:Tag(grandparent)
|
|
111
102
|
binder:Tag(child) -- child is bound too, but must be skipped
|
|
112
|
-
|
|
103
|
+
controller.boot()
|
|
113
104
|
|
|
114
105
|
expect(BinderUtils.findFirstAncestor(binder, child)).toEqual(binder:Get(grandparent))
|
|
115
106
|
|
|
116
|
-
|
|
107
|
+
controller.destroy()
|
|
117
108
|
end)
|
|
118
109
|
|
|
119
110
|
it("returns nil when no ancestor is bound", function()
|
|
120
|
-
local
|
|
111
|
+
local controller = setup()
|
|
121
112
|
|
|
122
|
-
local parent =
|
|
123
|
-
local child =
|
|
124
|
-
local binder =
|
|
125
|
-
|
|
113
|
+
local parent = controller.newInstance()
|
|
114
|
+
local child = controller.newInstance(parent)
|
|
115
|
+
local binder = controller.newBinder()
|
|
116
|
+
controller.boot()
|
|
126
117
|
|
|
127
118
|
expect(BinderUtils.findFirstAncestor(binder, child)).toBeNil()
|
|
128
119
|
|
|
129
|
-
|
|
120
|
+
controller.destroy()
|
|
130
121
|
end)
|
|
131
122
|
|
|
132
123
|
it("throws for a non-instance child", function()
|
|
133
|
-
local
|
|
124
|
+
local controller = setup()
|
|
134
125
|
|
|
135
|
-
local binder =
|
|
136
|
-
|
|
126
|
+
local binder = controller.newBinder()
|
|
127
|
+
controller.boot()
|
|
137
128
|
expect(function()
|
|
138
129
|
BinderUtils.findFirstAncestor(binder, 5 :: any)
|
|
139
130
|
end).toThrow()
|
|
140
131
|
|
|
141
|
-
|
|
132
|
+
controller.destroy()
|
|
142
133
|
end)
|
|
143
134
|
end)
|
|
144
135
|
|
|
145
136
|
describe("BinderUtils.findFirstChild()", function()
|
|
146
137
|
it("returns the first bound child", function()
|
|
147
|
-
local
|
|
138
|
+
local controller = setup()
|
|
148
139
|
|
|
149
|
-
local parent =
|
|
150
|
-
local unboundChild =
|
|
151
|
-
local boundChild =
|
|
140
|
+
local parent = controller.newInstance()
|
|
141
|
+
local unboundChild = controller.newInstance(parent)
|
|
142
|
+
local boundChild = controller.newInstance(parent)
|
|
152
143
|
|
|
153
|
-
local binder =
|
|
144
|
+
local binder = controller.newBinder()
|
|
154
145
|
binder:Tag(boundChild)
|
|
155
|
-
|
|
146
|
+
controller.boot()
|
|
156
147
|
|
|
157
148
|
expect(BinderUtils.findFirstChild(binder, parent)).toEqual(binder:Get(boundChild))
|
|
158
149
|
expect(binder:Get(unboundChild)).toBeNil()
|
|
159
150
|
|
|
160
|
-
|
|
151
|
+
controller.destroy()
|
|
161
152
|
end)
|
|
162
153
|
|
|
163
154
|
it("returns nil when no child is bound", function()
|
|
164
|
-
local
|
|
155
|
+
local controller = setup()
|
|
165
156
|
|
|
166
|
-
local parent =
|
|
167
|
-
|
|
168
|
-
local binder =
|
|
169
|
-
|
|
157
|
+
local parent = controller.newInstance()
|
|
158
|
+
controller.newInstance(parent)
|
|
159
|
+
local binder = controller.newBinder()
|
|
160
|
+
controller.boot()
|
|
170
161
|
|
|
171
162
|
expect(BinderUtils.findFirstChild(binder, parent)).toBeNil()
|
|
172
163
|
|
|
173
|
-
|
|
164
|
+
controller.destroy()
|
|
174
165
|
end)
|
|
175
166
|
end)
|
|
176
167
|
|
|
177
168
|
describe("BinderUtils.getChildren()", function()
|
|
178
169
|
it("returns every bound child", function()
|
|
179
|
-
local
|
|
170
|
+
local controller = setup()
|
|
180
171
|
|
|
181
|
-
local parent =
|
|
182
|
-
local childA =
|
|
183
|
-
local childB =
|
|
184
|
-
|
|
172
|
+
local parent = controller.newInstance()
|
|
173
|
+
local childA = controller.newInstance(parent)
|
|
174
|
+
local childB = controller.newInstance(parent)
|
|
175
|
+
controller.newInstance(parent) -- unbound
|
|
185
176
|
|
|
186
|
-
local binder =
|
|
177
|
+
local binder = controller.newBinder()
|
|
187
178
|
binder:Tag(childA)
|
|
188
179
|
binder:Tag(childB)
|
|
189
|
-
|
|
180
|
+
controller.boot()
|
|
190
181
|
|
|
191
182
|
expect(#BinderUtils.getChildren(binder, parent)).toEqual(2)
|
|
192
183
|
|
|
193
|
-
|
|
184
|
+
controller.destroy()
|
|
194
185
|
end)
|
|
195
186
|
|
|
196
187
|
it("does not include bound descendants deeper than one level", function()
|
|
197
|
-
local
|
|
188
|
+
local controller = setup()
|
|
198
189
|
|
|
199
|
-
local parent =
|
|
200
|
-
local child =
|
|
201
|
-
local grandchild =
|
|
190
|
+
local parent = controller.newInstance()
|
|
191
|
+
local child = controller.newInstance(parent)
|
|
192
|
+
local grandchild = controller.newInstance(child)
|
|
202
193
|
|
|
203
|
-
local binder =
|
|
194
|
+
local binder = controller.newBinder()
|
|
204
195
|
binder:Tag(grandchild)
|
|
205
|
-
|
|
196
|
+
controller.boot()
|
|
206
197
|
|
|
207
198
|
expect(#BinderUtils.getChildren(binder, parent)).toEqual(0)
|
|
208
199
|
|
|
209
|
-
|
|
200
|
+
controller.destroy()
|
|
210
201
|
end)
|
|
211
202
|
end)
|
|
212
203
|
|
|
213
204
|
describe("BinderUtils.getDescendants()", function()
|
|
214
205
|
it("returns bound instances at any depth", function()
|
|
215
|
-
local
|
|
206
|
+
local controller = setup()
|
|
216
207
|
|
|
217
|
-
local parent =
|
|
218
|
-
local child =
|
|
219
|
-
local grandchild =
|
|
208
|
+
local parent = controller.newInstance()
|
|
209
|
+
local child = controller.newInstance(parent)
|
|
210
|
+
local grandchild = controller.newInstance(child)
|
|
220
211
|
|
|
221
|
-
local binder =
|
|
212
|
+
local binder = controller.newBinder()
|
|
222
213
|
binder:Tag(child)
|
|
223
214
|
binder:Tag(grandchild)
|
|
224
|
-
|
|
215
|
+
controller.boot()
|
|
225
216
|
|
|
226
217
|
expect(#BinderUtils.getDescendants(binder, parent)).toEqual(2)
|
|
227
218
|
|
|
228
|
-
|
|
219
|
+
controller.destroy()
|
|
229
220
|
end)
|
|
230
221
|
end)
|
|
231
222
|
|
|
232
223
|
describe("BinderUtils.mapBinderListToTable()", function()
|
|
233
224
|
it("keys binders by their tag", function()
|
|
234
|
-
local
|
|
225
|
+
local controller = setup()
|
|
235
226
|
|
|
236
|
-
local binderA =
|
|
237
|
-
local binderB =
|
|
238
|
-
|
|
227
|
+
local binderA = controller.newBinder()
|
|
228
|
+
local binderB = controller.newBinder()
|
|
229
|
+
controller.boot()
|
|
239
230
|
|
|
240
231
|
local map = BinderUtils.mapBinderListToTable({ binderA, binderB })
|
|
241
232
|
expect(map[binderA:GetTag()]).toEqual(binderA)
|
|
242
233
|
expect(map[binderB:GetTag()]).toEqual(binderB)
|
|
243
234
|
|
|
244
|
-
|
|
235
|
+
controller.destroy()
|
|
245
236
|
end)
|
|
246
237
|
end)
|
|
247
238
|
|
|
248
239
|
describe("BinderUtils.getMappedFromList()", function()
|
|
249
240
|
it("resolves bound values across an instance list by tag", function()
|
|
250
|
-
local
|
|
241
|
+
local controller = setup()
|
|
251
242
|
|
|
252
|
-
local instA =
|
|
253
|
-
local instB =
|
|
254
|
-
local binderA =
|
|
255
|
-
local binderB =
|
|
243
|
+
local instA = controller.newInstance()
|
|
244
|
+
local instB = controller.newInstance()
|
|
245
|
+
local binderA = controller.newBinder()
|
|
246
|
+
local binderB = controller.newBinder()
|
|
256
247
|
binderA:Tag(instA)
|
|
257
248
|
binderB:Tag(instB)
|
|
258
|
-
|
|
249
|
+
controller.boot()
|
|
259
250
|
|
|
260
251
|
local tagsMap = BinderUtils.mapBinderListToTable({ binderA, binderB })
|
|
261
|
-
local objects = BinderUtils.getMappedFromList(tagsMap, { instA, instB,
|
|
252
|
+
local objects = BinderUtils.getMappedFromList(tagsMap, { instA, instB, controller.newInstance() })
|
|
262
253
|
|
|
263
254
|
expect(#objects).toEqual(2)
|
|
264
255
|
|
|
265
|
-
|
|
256
|
+
controller.destroy()
|
|
266
257
|
end)
|
|
267
258
|
end)
|
|
268
259
|
|
|
269
260
|
describe("BinderUtils.getChildrenOfBinders()", function()
|
|
270
261
|
it("returns children bound by any binder in the list", function()
|
|
271
|
-
local
|
|
262
|
+
local controller = setup()
|
|
272
263
|
|
|
273
|
-
local parent =
|
|
274
|
-
local childA =
|
|
275
|
-
local childB =
|
|
264
|
+
local parent = controller.newInstance()
|
|
265
|
+
local childA = controller.newInstance(parent)
|
|
266
|
+
local childB = controller.newInstance(parent)
|
|
276
267
|
|
|
277
|
-
local binderA =
|
|
278
|
-
local binderB =
|
|
268
|
+
local binderA = controller.newBinder()
|
|
269
|
+
local binderB = controller.newBinder()
|
|
279
270
|
binderA:Tag(childA)
|
|
280
271
|
binderB:Tag(childB)
|
|
281
|
-
|
|
272
|
+
controller.boot()
|
|
282
273
|
|
|
283
274
|
expect(#BinderUtils.getChildrenOfBinders({ binderA, binderB }, parent)).toEqual(2)
|
|
284
275
|
|
|
285
|
-
|
|
276
|
+
controller.destroy()
|
|
286
277
|
end)
|
|
287
278
|
end)
|
|
288
279
|
|
|
289
280
|
describe("BinderUtils.getLinkedChildren()", function()
|
|
290
281
|
it("resolves bound targets of matching ObjectValue links", function()
|
|
291
|
-
local
|
|
282
|
+
local controller = setup()
|
|
292
283
|
|
|
293
|
-
local parent =
|
|
294
|
-
local target =
|
|
295
|
-
local binder =
|
|
284
|
+
local parent = controller.newInstance()
|
|
285
|
+
local target = controller.newInstance()
|
|
286
|
+
local binder = controller.newBinder()
|
|
296
287
|
binder:Tag(target)
|
|
297
288
|
|
|
298
|
-
local link =
|
|
289
|
+
local link = controller.newInstance(parent, "ObjectValue") :: ObjectValue
|
|
299
290
|
link.Name = "Link"
|
|
300
291
|
link.Value = target
|
|
301
|
-
|
|
292
|
+
controller.boot()
|
|
302
293
|
|
|
303
294
|
local objects = BinderUtils.getLinkedChildren(binder, "Link", parent)
|
|
304
295
|
expect(#objects).toEqual(1)
|
|
305
296
|
expect(objects[1]).toEqual(binder:Get(target))
|
|
306
297
|
|
|
307
|
-
|
|
298
|
+
controller.destroy()
|
|
308
299
|
end)
|
|
309
300
|
|
|
310
301
|
it("ignores links whose name does not match", function()
|
|
311
|
-
local
|
|
302
|
+
local controller = setup()
|
|
312
303
|
|
|
313
|
-
local parent =
|
|
314
|
-
local target =
|
|
315
|
-
local binder =
|
|
304
|
+
local parent = controller.newInstance()
|
|
305
|
+
local target = controller.newInstance()
|
|
306
|
+
local binder = controller.newBinder()
|
|
316
307
|
binder:Tag(target)
|
|
317
308
|
|
|
318
|
-
local link =
|
|
309
|
+
local link = controller.newInstance(parent, "ObjectValue") :: ObjectValue
|
|
319
310
|
link.Name = "OtherLink"
|
|
320
311
|
link.Value = target
|
|
321
|
-
|
|
312
|
+
controller.boot()
|
|
322
313
|
|
|
323
314
|
expect(#BinderUtils.getLinkedChildren(binder, "Link", parent)).toEqual(0)
|
|
324
315
|
|
|
325
|
-
|
|
316
|
+
controller.destroy()
|
|
326
317
|
end)
|
|
327
318
|
|
|
328
319
|
it("deduplicates when two links point to the same bound target", function()
|
|
329
|
-
local
|
|
320
|
+
local controller = setup()
|
|
330
321
|
|
|
331
|
-
local parent =
|
|
332
|
-
local target =
|
|
333
|
-
local binder =
|
|
322
|
+
local parent = controller.newInstance()
|
|
323
|
+
local target = controller.newInstance()
|
|
324
|
+
local binder = controller.newBinder()
|
|
334
325
|
binder:Tag(target)
|
|
335
326
|
|
|
336
327
|
for _ = 1, 2 do
|
|
337
|
-
local link =
|
|
328
|
+
local link = controller.newInstance(parent, "ObjectValue") :: ObjectValue
|
|
338
329
|
link.Name = "Link"
|
|
339
330
|
link.Value = target
|
|
340
331
|
end
|
|
341
|
-
|
|
332
|
+
controller.boot()
|
|
342
333
|
|
|
343
334
|
expect(#BinderUtils.getLinkedChildren(binder, "Link", parent)).toEqual(1)
|
|
344
335
|
|
|
345
|
-
|
|
336
|
+
controller.destroy()
|
|
346
337
|
end)
|
|
347
338
|
end)
|