@quenty/adorneeutils 3.3.5 → 3.3.6

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,1086 @@
1
+ --!strict
2
+ --[[
3
+ @class AdorneeUtils.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local AdorneeUtils = require("AdorneeUtils")
9
+ local Jest = require("Jest")
10
+ local Maid = require("Maid")
11
+
12
+ local describe = Jest.Globals.describe
13
+ local expect = Jest.Globals.expect
14
+ local it = Jest.Globals.it
15
+
16
+ local HANDLE_CFRAME = CFrame.new(5, 5, 5)
17
+ local HANDLE_SIZE = Vector3.new(1, 1, 2)
18
+ local BLADE_CFRAME = CFrame.new(50, 0, 0)
19
+ local BLADE_SIZE = Vector3.new(1, 1, 8)
20
+ local TOOL_BOUNDING_BOX_CFRAME = CFrame.new(27.5, 2.5, 1)
21
+ local TOOL_BOUNDING_BOX_SIZE = Vector3.new(46, 6, 10)
22
+
23
+ local MODEL_BOUNDING_BOX_CFRAME = CFrame.new(5, 0, 0)
24
+ local MODEL_BOUNDING_BOX_SIZE = Vector3.new(12, 2, 2)
25
+
26
+ local ROOT_PART_CFRAME = CFrame.new(1, 2, 3)
27
+ local CHARACTER_BOUNDING_BOX_SIZE = Vector3.new(2, 4, 1)
28
+
29
+ local ACCESSORY_HANDLE_CFRAME = CFrame.new(7, 8, 9)
30
+ local ACCESSORY_HANDLE_SIZE = Vector3.new(3, 3, 3)
31
+
32
+ local CLOTHING_PART_CFRAME = CFrame.new(20, 0, 0)
33
+ local CLOTHING_PART_SIZE = Vector3.new(4, 4, 4)
34
+
35
+ type Controller = {
36
+ newPart: (size: Vector3?, cframe: CFrame?, name: string?) -> BasePart,
37
+ newFolder: () -> Folder,
38
+ newModel: () -> (Model, BasePart, BasePart),
39
+ newEmptyModel: () -> Model,
40
+ newAttachment: (parent: Instance, cframe: CFrame?) -> Attachment,
41
+ newCharacter: () -> (Model, Humanoid, BasePart),
42
+ newOrphanHumanoid: () -> Humanoid,
43
+ newTool: () -> (Tool, BasePart, BasePart),
44
+ newHandlelessTool: () -> (Tool, BasePart),
45
+ newAccessory: () -> (Accessory, BasePart),
46
+ newClothing: () -> (Clothing, BasePart),
47
+ destroy: () -> (),
48
+ }
49
+
50
+ local function setup(): Controller
51
+ local maid = Maid.new()
52
+
53
+ local function newPart(size: Vector3?, cframe: CFrame?, name: string?): BasePart
54
+ local part = Instance.new("Part")
55
+ part.Anchored = true
56
+ part.Name = name or "Part"
57
+ part.Size = size or Vector3.new(2, 2, 2)
58
+ part.CFrame = cframe or CFrame.new()
59
+ maid:GiveTask(part)
60
+ return part
61
+ end
62
+
63
+ local controller: Controller = {
64
+ newPart = newPart,
65
+
66
+ newFolder = function()
67
+ local folder = Instance.new("Folder")
68
+ maid:GiveTask(folder)
69
+ return folder
70
+ end,
71
+
72
+ newModel = function()
73
+ local model = Instance.new("Model")
74
+
75
+ local first = newPart(Vector3.new(2, 2, 2), CFrame.new(0, 0, 0), "First")
76
+ first.Parent = model
77
+
78
+ local second = newPart(Vector3.new(2, 2, 2), CFrame.new(10, 0, 0), "Second")
79
+ second.Parent = model
80
+
81
+ maid:GiveTask(model)
82
+ return model, first, second
83
+ end,
84
+
85
+ newEmptyModel = function()
86
+ local model = Instance.new("Model")
87
+ maid:GiveTask(model)
88
+ return model
89
+ end,
90
+
91
+ newAttachment = function(parent, cframe)
92
+ local attachment = Instance.new("Attachment")
93
+ attachment.CFrame = cframe or CFrame.new(0, 1, 0)
94
+ attachment.Parent = parent
95
+ maid:GiveTask(attachment)
96
+ return attachment
97
+ end,
98
+
99
+ newCharacter = function()
100
+ local character = Instance.new("Model")
101
+
102
+ local rootPart = newPart(Vector3.new(2, 2, 1), ROOT_PART_CFRAME, "HumanoidRootPart")
103
+ rootPart.Parent = character
104
+
105
+ local torso = newPart(Vector3.new(2, 2, 1), CFrame.new(1, 4, 3), "Torso")
106
+ torso.Parent = character
107
+
108
+ local humanoid = Instance.new("Humanoid")
109
+ humanoid.Parent = character
110
+
111
+ maid:GiveTask(character)
112
+ return character, humanoid, rootPart
113
+ end,
114
+
115
+ newOrphanHumanoid = function()
116
+ local humanoid = Instance.new("Humanoid")
117
+ maid:GiveTask(humanoid)
118
+ return humanoid
119
+ end,
120
+
121
+ newTool = function()
122
+ local tool = Instance.new("Tool")
123
+
124
+ local blade = newPart(BLADE_SIZE, BLADE_CFRAME, "Blade")
125
+ blade.Parent = tool
126
+
127
+ local handle = newPart(HANDLE_SIZE, HANDLE_CFRAME, "Handle")
128
+ handle.Parent = tool
129
+
130
+ maid:GiveTask(tool)
131
+ return tool, handle, blade
132
+ end,
133
+
134
+ newHandlelessTool = function()
135
+ local tool = Instance.new("Tool")
136
+
137
+ local blade = newPart(BLADE_SIZE, BLADE_CFRAME, "Blade")
138
+ blade.Parent = tool
139
+
140
+ maid:GiveTask(tool)
141
+ return tool, blade
142
+ end,
143
+
144
+ newAccessory = function()
145
+ local accessory = Instance.new("Accessory")
146
+
147
+ local handle = newPart(ACCESSORY_HANDLE_SIZE, ACCESSORY_HANDLE_CFRAME, "Handle")
148
+ handle.Parent = accessory
149
+
150
+ maid:GiveTask(accessory)
151
+ return accessory, handle
152
+ end,
153
+
154
+ newClothing = function()
155
+ local clothing = Instance.new("Shirt")
156
+
157
+ local part = newPart(CLOTHING_PART_SIZE, CLOTHING_PART_CFRAME, "ClothingPart")
158
+ part.Parent = clothing
159
+
160
+ maid:GiveTask(clothing)
161
+ return clothing, part
162
+ end,
163
+
164
+ destroy = function()
165
+ maid:DoCleaning()
166
+ end,
167
+ }
168
+
169
+ return controller
170
+ end
171
+
172
+ describe("Tool inheriting from Model", function()
173
+ it("still reports as a model", function()
174
+ local controller = setup()
175
+ local tool = controller.newTool()
176
+
177
+ expect(tool:IsA("Model")).toEqual(true)
178
+
179
+ controller.destroy()
180
+ end)
181
+
182
+ it("adorns to the handle rather than the model bounding box", function()
183
+ local controller = setup()
184
+ local tool, handle = controller.newTool()
185
+
186
+ expect(AdorneeUtils.getCenter(tool)).toEqual(handle.Position)
187
+ expect(AdorneeUtils.getPart(tool)).toEqual(handle)
188
+ expect(AdorneeUtils.getPartCFrame(tool)).toEqual(handle.CFrame)
189
+ expect(AdorneeUtils.getAlignedSize(tool)).toEqual(handle.Size)
190
+ expect(AdorneeUtils.getRenderAdornee(tool)).toEqual(handle)
191
+
192
+ controller.destroy()
193
+ end)
194
+
195
+ it("does not fall back to another part when the tool has no handle", function()
196
+ local controller = setup()
197
+ local tool, blade = controller.newHandlelessTool()
198
+
199
+ expect(tool:FindFirstChildWhichIsA("BasePart")).toEqual(blade)
200
+ expect(AdorneeUtils.getCenter(tool)).toBeNil()
201
+ expect(AdorneeUtils.getPart(tool)).toBeNil()
202
+ expect(AdorneeUtils.getAlignedSize(tool)).toBeNil()
203
+ expect(AdorneeUtils.getRenderAdornee(tool)).toBeNil()
204
+
205
+ controller.destroy()
206
+ end)
207
+
208
+ it("adorns to the handle even when the tool has a primary part", function()
209
+ local controller = setup()
210
+ local tool, handle, blade = controller.newTool()
211
+ tool.PrimaryPart = blade
212
+
213
+ expect(AdorneeUtils.getPart(tool)).toEqual(handle)
214
+
215
+ controller.destroy()
216
+ end)
217
+
218
+ it("leaves plain models on the model path", function()
219
+ local controller = setup()
220
+ local model = controller.newModel()
221
+
222
+ expect(AdorneeUtils.getCenter(model)).toEqual(MODEL_BOUNDING_BOX_CFRAME.Position)
223
+ expect(AdorneeUtils.getAlignedSize(model)).toEqual(MODEL_BOUNDING_BOX_SIZE)
224
+ expect(AdorneeUtils.getRenderAdornee(model)).toEqual(model)
225
+
226
+ controller.destroy()
227
+ end)
228
+ end)
229
+
230
+ describe("AdorneeUtils.getCenter", function()
231
+ it("returns the position of a base part", function()
232
+ local controller = setup()
233
+ local part = controller.newPart(nil, CFrame.new(1, 2, 3))
234
+
235
+ expect(AdorneeUtils.getCenter(part)).toEqual(Vector3.new(1, 2, 3))
236
+
237
+ controller.destroy()
238
+ end)
239
+
240
+ it("returns the bounding box center of a model", function()
241
+ local controller = setup()
242
+ local model = controller.newModel()
243
+
244
+ expect(AdorneeUtils.getCenter(model)).toEqual(MODEL_BOUNDING_BOX_CFRAME.Position)
245
+
246
+ controller.destroy()
247
+ end)
248
+
249
+ it("returns the world position of an attachment", function()
250
+ local controller = setup()
251
+ local part = controller.newPart(nil, CFrame.new(10, 0, 0))
252
+ local attachment = controller.newAttachment(part, CFrame.new(0, 1, 0))
253
+
254
+ expect(AdorneeUtils.getCenter(attachment)).toEqual(Vector3.new(10, 1, 0))
255
+
256
+ controller.destroy()
257
+ end)
258
+
259
+ it("returns the root part position of a humanoid", function()
260
+ local controller = setup()
261
+ local _character, humanoid = controller.newCharacter()
262
+
263
+ expect(AdorneeUtils.getCenter(humanoid)).toEqual(ROOT_PART_CFRAME.Position)
264
+
265
+ controller.destroy()
266
+ end)
267
+
268
+ it("returns nil for a humanoid with no root part", function()
269
+ local controller = setup()
270
+ local humanoid = controller.newOrphanHumanoid()
271
+
272
+ expect(AdorneeUtils.getCenter(humanoid)).toBeNil()
273
+
274
+ controller.destroy()
275
+ end)
276
+
277
+ it("returns the handle position of an accessory", function()
278
+ local controller = setup()
279
+ local accessory = controller.newAccessory()
280
+
281
+ expect(AdorneeUtils.getCenter(accessory)).toEqual(ACCESSORY_HANDLE_CFRAME.Position)
282
+
283
+ controller.destroy()
284
+ end)
285
+
286
+ it("returns nil for an accessory with no part", function()
287
+ local controller = setup()
288
+ local accessory = Instance.new("Accessory")
289
+
290
+ expect(AdorneeUtils.getCenter(accessory)).toBeNil()
291
+
292
+ accessory:Destroy()
293
+ controller.destroy()
294
+ end)
295
+
296
+ it("returns the part position of clothing", function()
297
+ local controller = setup()
298
+ local clothing = controller.newClothing()
299
+
300
+ expect(AdorneeUtils.getCenter(clothing)).toEqual(CLOTHING_PART_CFRAME.Position)
301
+
302
+ controller.destroy()
303
+ end)
304
+
305
+ it("returns the handle position of a tool", function()
306
+ local controller = setup()
307
+ local tool = controller.newTool()
308
+
309
+ expect(AdorneeUtils.getCenter(tool)).toEqual(HANDLE_CFRAME.Position)
310
+
311
+ controller.destroy()
312
+ end)
313
+
314
+ it("returns nil when a tool's handle is not a base part", function()
315
+ local controller = setup()
316
+ local tool = controller.newHandlelessTool()
317
+
318
+ local decoy = Instance.new("Folder")
319
+ decoy.Name = "Handle"
320
+ decoy.Parent = tool
321
+
322
+ expect(AdorneeUtils.getCenter(tool)).toBeNil()
323
+
324
+ controller.destroy()
325
+ end)
326
+
327
+ it("returns nil for an unsupported adornee", function()
328
+ local controller = setup()
329
+ local folder = controller.newFolder()
330
+
331
+ expect(AdorneeUtils.getCenter(folder)).toBeNil()
332
+
333
+ controller.destroy()
334
+ end)
335
+
336
+ it("throws for a non-instance", function()
337
+ expect(function()
338
+ AdorneeUtils.getCenter(nil :: any)
339
+ end).toThrow()
340
+
341
+ expect(function()
342
+ AdorneeUtils.getCenter(Vector3.zero :: any)
343
+ end).toThrow()
344
+ end)
345
+ end)
346
+
347
+ describe("AdorneeUtils.getBoundingBox", function()
348
+ it("returns the model bounding box", function()
349
+ local controller = setup()
350
+ local model = controller.newModel()
351
+
352
+ local cframe, size = AdorneeUtils.getBoundingBox(model)
353
+
354
+ expect(cframe).toEqual(MODEL_BOUNDING_BOX_CFRAME)
355
+ expect(size).toEqual(MODEL_BOUNDING_BOX_SIZE)
356
+
357
+ controller.destroy()
358
+ end)
359
+
360
+ it("returns a zero sized box at an attachment's world cframe", function()
361
+ local controller = setup()
362
+ local part = controller.newPart(nil, CFrame.new(10, 0, 0))
363
+ local attachment = controller.newAttachment(part, CFrame.new(0, 1, 0))
364
+
365
+ local cframe, size = AdorneeUtils.getBoundingBox(attachment)
366
+
367
+ expect(cframe).toEqual(CFrame.new(10, 1, 0))
368
+ expect(size).toEqual(Vector3.zero)
369
+
370
+ controller.destroy()
371
+ end)
372
+
373
+ it("returns the cframe and size of a base part", function()
374
+ local controller = setup()
375
+ local part = controller.newPart(Vector3.new(4, 1, 2), CFrame.new(1, 2, 3))
376
+
377
+ local cframe, size = AdorneeUtils.getBoundingBox(part)
378
+
379
+ expect(cframe).toEqual(CFrame.new(1, 2, 3))
380
+ expect(size).toEqual(Vector3.new(4, 1, 2))
381
+
382
+ controller.destroy()
383
+ end)
384
+
385
+ it("returns the handle box of a tool rather than its model bounding box", function()
386
+ local controller = setup()
387
+ local tool = controller.newTool()
388
+
389
+ local modelCFrame, modelSize = tool:GetBoundingBox()
390
+
391
+ expect(modelCFrame).toEqual(TOOL_BOUNDING_BOX_CFRAME)
392
+ expect(modelSize).toEqual(TOOL_BOUNDING_BOX_SIZE)
393
+
394
+ local cframe, size = AdorneeUtils.getBoundingBox(tool)
395
+
396
+ expect(cframe).toEqual(HANDLE_CFRAME)
397
+ expect(size).toEqual(HANDLE_SIZE)
398
+
399
+ controller.destroy()
400
+ end)
401
+
402
+ it("returns nil for a tool with no handle", function()
403
+ local controller = setup()
404
+ local tool = controller.newHandlelessTool()
405
+
406
+ local cframe, size = AdorneeUtils.getBoundingBox(tool)
407
+
408
+ expect(cframe).toBeNil()
409
+ expect(size).toBeNil()
410
+
411
+ controller.destroy()
412
+ end)
413
+
414
+ it("returns the root part cframe and the character size for a humanoid", function()
415
+ local controller = setup()
416
+ local _character, humanoid = controller.newCharacter()
417
+
418
+ local cframe, size = AdorneeUtils.getBoundingBox(humanoid)
419
+
420
+ expect(cframe).toEqual(ROOT_PART_CFRAME)
421
+ expect(size).toEqual(CHARACTER_BOUNDING_BOX_SIZE)
422
+
423
+ controller.destroy()
424
+ end)
425
+
426
+ it("returns nil for an unsupported adornee", function()
427
+ local controller = setup()
428
+ local folder = controller.newFolder()
429
+
430
+ local cframe, size = AdorneeUtils.getBoundingBox(folder)
431
+
432
+ expect(cframe).toBeNil()
433
+ expect(size).toBeNil()
434
+
435
+ controller.destroy()
436
+ end)
437
+ end)
438
+
439
+ describe("AdorneeUtils.isPartOfAdornee", function()
440
+ it("returns true when the part is the adornee", function()
441
+ local controller = setup()
442
+ local part = controller.newPart()
443
+
444
+ expect(AdorneeUtils.isPartOfAdornee(part, part)).toEqual(true)
445
+
446
+ controller.destroy()
447
+ end)
448
+
449
+ it("returns true for a descendant part", function()
450
+ local controller = setup()
451
+ local model, first = controller.newModel()
452
+
453
+ expect(AdorneeUtils.isPartOfAdornee(model, first)).toEqual(true)
454
+
455
+ controller.destroy()
456
+ end)
457
+
458
+ it("returns true for a deeply nested part", function()
459
+ local controller = setup()
460
+ local model = controller.newEmptyModel()
461
+
462
+ local folder = Instance.new("Folder")
463
+ folder.Parent = model
464
+
465
+ local nested = controller.newPart()
466
+ nested.Parent = folder
467
+
468
+ expect(AdorneeUtils.isPartOfAdornee(model, nested)).toEqual(true)
469
+
470
+ controller.destroy()
471
+ end)
472
+
473
+ it("returns false for an unrelated part", function()
474
+ local controller = setup()
475
+ local model = controller.newModel()
476
+ local other = controller.newPart()
477
+
478
+ expect(AdorneeUtils.isPartOfAdornee(model, other)).toEqual(false)
479
+
480
+ controller.destroy()
481
+ end)
482
+
483
+ it("returns true for a part of the humanoid's character", function()
484
+ local controller = setup()
485
+ local _character, humanoid, rootPart = controller.newCharacter()
486
+
487
+ expect(AdorneeUtils.isPartOfAdornee(humanoid, rootPart)).toEqual(true)
488
+
489
+ controller.destroy()
490
+ end)
491
+
492
+ it("returns false for a part outside the humanoid's character", function()
493
+ local controller = setup()
494
+ local _character, humanoid = controller.newCharacter()
495
+ local other = controller.newPart()
496
+
497
+ expect(AdorneeUtils.isPartOfAdornee(humanoid, other)).toEqual(false)
498
+
499
+ controller.destroy()
500
+ end)
501
+
502
+ it("returns false for a humanoid with no parent", function()
503
+ local controller = setup()
504
+ local humanoid = controller.newOrphanHumanoid()
505
+ local part = controller.newPart()
506
+
507
+ expect(AdorneeUtils.isPartOfAdornee(humanoid, part)).toEqual(false)
508
+
509
+ controller.destroy()
510
+ end)
511
+
512
+ it("returns true for the parts of a tool", function()
513
+ local controller = setup()
514
+ local tool, handle, blade = controller.newTool()
515
+
516
+ expect(AdorneeUtils.isPartOfAdornee(tool, handle)).toEqual(true)
517
+ expect(AdorneeUtils.isPartOfAdornee(tool, blade)).toEqual(true)
518
+
519
+ controller.destroy()
520
+ end)
521
+
522
+ it("throws for a bad part", function()
523
+ local controller = setup()
524
+ local part = controller.newPart()
525
+ local folder = controller.newFolder()
526
+
527
+ expect(function()
528
+ AdorneeUtils.isPartOfAdornee(part, nil :: any)
529
+ end).toThrow()
530
+
531
+ expect(function()
532
+ AdorneeUtils.isPartOfAdornee(part, folder :: any)
533
+ end).toThrow()
534
+
535
+ controller.destroy()
536
+ end)
537
+ end)
538
+
539
+ describe("AdorneeUtils.getParts", function()
540
+ it("returns the base part itself", function()
541
+ local controller = setup()
542
+ local part = controller.newPart()
543
+
544
+ expect(AdorneeUtils.getParts(part)).toEqual({ part })
545
+
546
+ controller.destroy()
547
+ end)
548
+
549
+ it("includes the descendants of a base part", function()
550
+ local controller = setup()
551
+ local part = controller.newPart()
552
+ local child = controller.newPart()
553
+ child.Parent = part
554
+
555
+ expect(AdorneeUtils.getParts(part)).toEqual({ part, child })
556
+
557
+ controller.destroy()
558
+ end)
559
+
560
+ it("returns every part of a model", function()
561
+ local controller = setup()
562
+ local model, first, second = controller.newModel()
563
+
564
+ expect(AdorneeUtils.getParts(model)).toEqual({ first, second })
565
+
566
+ controller.destroy()
567
+ end)
568
+
569
+ it("returns the nested parts of a model", function()
570
+ local controller = setup()
571
+ local model = controller.newEmptyModel()
572
+
573
+ local folder = Instance.new("Folder")
574
+ folder.Parent = model
575
+
576
+ local nested = controller.newPart()
577
+ nested.Parent = folder
578
+
579
+ expect(AdorneeUtils.getParts(model)).toEqual({ nested })
580
+
581
+ controller.destroy()
582
+ end)
583
+
584
+ it("returns the character's parts for a humanoid", function()
585
+ local controller = setup()
586
+ local _character, humanoid, rootPart = controller.newCharacter()
587
+
588
+ local parts = AdorneeUtils.getParts(humanoid)
589
+
590
+ expect(#parts).toEqual(2)
591
+ expect(parts[1]).toEqual(rootPart)
592
+
593
+ controller.destroy()
594
+ end)
595
+
596
+ it("returns an empty list for a humanoid with no parent", function()
597
+ local controller = setup()
598
+ local humanoid = controller.newOrphanHumanoid()
599
+
600
+ expect(AdorneeUtils.getParts(humanoid)).toEqual({})
601
+
602
+ controller.destroy()
603
+ end)
604
+
605
+ it("returns every part of a tool", function()
606
+ local controller = setup()
607
+ local tool, handle, blade = controller.newTool()
608
+
609
+ expect(AdorneeUtils.getParts(tool)).toEqual({ blade, handle })
610
+
611
+ controller.destroy()
612
+ end)
613
+
614
+ it("returns an empty list for an adornee with no parts", function()
615
+ local controller = setup()
616
+ local folder = controller.newFolder()
617
+
618
+ expect(AdorneeUtils.getParts(folder)).toEqual({})
619
+
620
+ controller.destroy()
621
+ end)
622
+
623
+ it("throws for a non-instance", function()
624
+ expect(function()
625
+ AdorneeUtils.getParts(nil :: any)
626
+ end).toThrow()
627
+ end)
628
+ end)
629
+
630
+ describe("AdorneeUtils.getAlignedSize", function()
631
+ it("returns the bounding box size of a model", function()
632
+ local controller = setup()
633
+ local model = controller.newModel()
634
+
635
+ expect(AdorneeUtils.getAlignedSize(model)).toEqual(MODEL_BOUNDING_BOX_SIZE)
636
+
637
+ controller.destroy()
638
+ end)
639
+
640
+ it("returns the character bounding box size for a humanoid", function()
641
+ local controller = setup()
642
+ local _character, humanoid = controller.newCharacter()
643
+
644
+ expect(AdorneeUtils.getAlignedSize(humanoid)).toEqual(CHARACTER_BOUNDING_BOX_SIZE)
645
+
646
+ controller.destroy()
647
+ end)
648
+
649
+ it("returns nil for a humanoid whose parent is not a model", function()
650
+ local controller = setup()
651
+ local humanoid = controller.newOrphanHumanoid()
652
+ humanoid.Parent = controller.newFolder()
653
+
654
+ expect(AdorneeUtils.getAlignedSize(humanoid)).toBeNil()
655
+
656
+ controller.destroy()
657
+ end)
658
+
659
+ it("returns nil for a humanoid with no parent", function()
660
+ local controller = setup()
661
+ local humanoid = controller.newOrphanHumanoid()
662
+
663
+ expect(AdorneeUtils.getAlignedSize(humanoid)).toBeNil()
664
+
665
+ controller.destroy()
666
+ end)
667
+
668
+ it("returns the size of a base part", function()
669
+ local controller = setup()
670
+ local part = controller.newPart(Vector3.new(4, 1, 2))
671
+
672
+ expect(AdorneeUtils.getAlignedSize(part)).toEqual(Vector3.new(4, 1, 2))
673
+
674
+ controller.destroy()
675
+ end)
676
+
677
+ it("returns the ancestor part size for an attachment", function()
678
+ local controller = setup()
679
+ local part = controller.newPart(Vector3.new(4, 1, 2))
680
+ local attachment = controller.newAttachment(part)
681
+
682
+ expect(AdorneeUtils.getAlignedSize(attachment)).toEqual(Vector3.new(4, 1, 2))
683
+
684
+ controller.destroy()
685
+ end)
686
+
687
+ it("returns the handle size of a tool", function()
688
+ local controller = setup()
689
+ local tool = controller.newTool()
690
+
691
+ expect(AdorneeUtils.getAlignedSize(tool)).toEqual(HANDLE_SIZE)
692
+
693
+ controller.destroy()
694
+ end)
695
+
696
+ it("returns nil for a tool with no handle", function()
697
+ local controller = setup()
698
+ local tool = controller.newHandlelessTool()
699
+
700
+ expect(AdorneeUtils.getAlignedSize(tool)).toBeNil()
701
+
702
+ controller.destroy()
703
+ end)
704
+
705
+ it("returns nil for an unsupported adornee", function()
706
+ local controller = setup()
707
+ local folder = controller.newFolder()
708
+
709
+ expect(AdorneeUtils.getAlignedSize(folder)).toBeNil()
710
+
711
+ controller.destroy()
712
+ end)
713
+ end)
714
+
715
+ describe("AdorneeUtils.getPartCFrame", function()
716
+ it("returns the cframe of a base part", function()
717
+ local controller = setup()
718
+ local part = controller.newPart(nil, CFrame.new(1, 2, 3))
719
+
720
+ expect(AdorneeUtils.getPartCFrame(part)).toEqual(CFrame.new(1, 2, 3))
721
+
722
+ controller.destroy()
723
+ end)
724
+
725
+ it("returns the handle cframe of a tool", function()
726
+ local controller = setup()
727
+ local tool = controller.newTool()
728
+
729
+ expect(AdorneeUtils.getPartCFrame(tool)).toEqual(HANDLE_CFRAME)
730
+
731
+ controller.destroy()
732
+ end)
733
+
734
+ it("returns the root part cframe of a humanoid", function()
735
+ local controller = setup()
736
+ local _character, humanoid = controller.newCharacter()
737
+
738
+ expect(AdorneeUtils.getPartCFrame(humanoid)).toEqual(ROOT_PART_CFRAME)
739
+
740
+ controller.destroy()
741
+ end)
742
+
743
+ it("returns nil for an adornee with no part", function()
744
+ local controller = setup()
745
+ local folder = controller.newFolder()
746
+
747
+ expect(AdorneeUtils.getPartCFrame(folder)).toBeNil()
748
+
749
+ controller.destroy()
750
+ end)
751
+
752
+ it("throws for a non-instance", function()
753
+ expect(function()
754
+ AdorneeUtils.getPartCFrame(nil :: any)
755
+ end).toThrow()
756
+ end)
757
+ end)
758
+
759
+ describe("AdorneeUtils.getPartPosition", function()
760
+ it("returns the position of a base part", function()
761
+ local controller = setup()
762
+ local part = controller.newPart(nil, CFrame.new(1, 2, 3))
763
+
764
+ expect(AdorneeUtils.getPartPosition(part)).toEqual(Vector3.new(1, 2, 3))
765
+
766
+ controller.destroy()
767
+ end)
768
+
769
+ it("returns the primary part position of a model", function()
770
+ local controller = setup()
771
+ local model, _first, second = controller.newModel()
772
+ model.PrimaryPart = second
773
+
774
+ expect(AdorneeUtils.getPartPosition(model)).toEqual(second.Position)
775
+
776
+ controller.destroy()
777
+ end)
778
+
779
+ it("returns the root part position of a humanoid", function()
780
+ local controller = setup()
781
+ local _character, humanoid = controller.newCharacter()
782
+
783
+ expect(AdorneeUtils.getPartPosition(humanoid)).toEqual(ROOT_PART_CFRAME.Position)
784
+
785
+ controller.destroy()
786
+ end)
787
+
788
+ it("returns nil for an adornee with no part", function()
789
+ local controller = setup()
790
+ local folder = controller.newFolder()
791
+
792
+ expect(AdorneeUtils.getPartPosition(folder)).toBeNil()
793
+
794
+ controller.destroy()
795
+ end)
796
+
797
+ it("throws for a non-instance", function()
798
+ expect(function()
799
+ AdorneeUtils.getPartPosition(nil :: any)
800
+ end).toThrow()
801
+ end)
802
+ end)
803
+
804
+ describe("AdorneeUtils.getPartVelocity", function()
805
+ it("returns the assembly linear velocity of a base part", function()
806
+ local controller = setup()
807
+ local part = controller.newPart()
808
+ part.Anchored = false
809
+ part.AssemblyLinearVelocity = Vector3.new(1, 2, 3)
810
+
811
+ expect(AdorneeUtils.getPartVelocity(part)).toEqual(Vector3.new(1, 2, 3))
812
+
813
+ controller.destroy()
814
+ end)
815
+
816
+ it("returns zero for an anchored part", function()
817
+ local controller = setup()
818
+ local part = controller.newPart()
819
+
820
+ expect(AdorneeUtils.getPartVelocity(part)).toEqual(Vector3.zero)
821
+
822
+ controller.destroy()
823
+ end)
824
+
825
+ it("returns the handle velocity of a tool", function()
826
+ local controller = setup()
827
+ local tool, handle = controller.newTool()
828
+ handle.Anchored = false
829
+ handle.AssemblyLinearVelocity = Vector3.new(0, 5, 0)
830
+
831
+ expect(AdorneeUtils.getPartVelocity(tool)).toEqual(Vector3.new(0, 5, 0))
832
+
833
+ controller.destroy()
834
+ end)
835
+
836
+ it("returns nil for an adornee with no part", function()
837
+ local controller = setup()
838
+ local folder = controller.newFolder()
839
+
840
+ expect(AdorneeUtils.getPartVelocity(folder)).toBeNil()
841
+
842
+ controller.destroy()
843
+ end)
844
+ end)
845
+
846
+ describe("AdorneeUtils.getPart", function()
847
+ it("returns a base part itself", function()
848
+ local controller = setup()
849
+ local part = controller.newPart()
850
+
851
+ expect(AdorneeUtils.getPart(part)).toEqual(part)
852
+
853
+ controller.destroy()
854
+ end)
855
+
856
+ it("returns a model's primary part", function()
857
+ local controller = setup()
858
+ local model, _first, second = controller.newModel()
859
+ model.PrimaryPart = second
860
+
861
+ expect(AdorneeUtils.getPart(model)).toEqual(second)
862
+
863
+ controller.destroy()
864
+ end)
865
+
866
+ it("returns a model's first base part when there is no primary part", function()
867
+ local controller = setup()
868
+ local model, first = controller.newModel()
869
+
870
+ expect(AdorneeUtils.getPart(model)).toEqual(first)
871
+
872
+ controller.destroy()
873
+ end)
874
+
875
+ it("returns nil for a model with no parts", function()
876
+ local controller = setup()
877
+ local model = controller.newEmptyModel()
878
+
879
+ expect(AdorneeUtils.getPart(model)).toBeNil()
880
+
881
+ controller.destroy()
882
+ end)
883
+
884
+ it("returns nil for a model whose parts are not direct children", function()
885
+ local controller = setup()
886
+ local model = controller.newEmptyModel()
887
+
888
+ local folder = Instance.new("Folder")
889
+ folder.Parent = model
890
+
891
+ local nested = controller.newPart()
892
+ nested.Parent = folder
893
+
894
+ expect(AdorneeUtils.getPart(model)).toBeNil()
895
+
896
+ controller.destroy()
897
+ end)
898
+
899
+ it("returns the ancestor part of an attachment", function()
900
+ local controller = setup()
901
+ local part = controller.newPart()
902
+ local attachment = controller.newAttachment(part)
903
+
904
+ expect(AdorneeUtils.getPart(attachment)).toEqual(part)
905
+
906
+ controller.destroy()
907
+ end)
908
+
909
+ it("returns nil for an attachment with no ancestor part", function()
910
+ local controller = setup()
911
+ local folder = controller.newFolder()
912
+ local attachment = controller.newAttachment(folder)
913
+
914
+ expect(AdorneeUtils.getPart(attachment)).toBeNil()
915
+
916
+ controller.destroy()
917
+ end)
918
+
919
+ it("returns the root part of a humanoid", function()
920
+ local controller = setup()
921
+ local _character, humanoid, rootPart = controller.newCharacter()
922
+
923
+ expect(AdorneeUtils.getPart(humanoid)).toEqual(rootPart)
924
+
925
+ controller.destroy()
926
+ end)
927
+
928
+ it("returns nil for a humanoid with no root part", function()
929
+ local controller = setup()
930
+ local humanoid = controller.newOrphanHumanoid()
931
+
932
+ expect(AdorneeUtils.getPart(humanoid)).toBeNil()
933
+
934
+ controller.destroy()
935
+ end)
936
+
937
+ it("returns the handle of an accessory", function()
938
+ local controller = setup()
939
+ local accessory, handle = controller.newAccessory()
940
+
941
+ expect(AdorneeUtils.getPart(accessory)).toEqual(handle)
942
+
943
+ controller.destroy()
944
+ end)
945
+
946
+ it("returns the part of clothing", function()
947
+ local controller = setup()
948
+ local clothing, part = controller.newClothing()
949
+
950
+ expect(AdorneeUtils.getPart(clothing)).toEqual(part)
951
+
952
+ controller.destroy()
953
+ end)
954
+
955
+ it("returns the handle of a tool ahead of any other part", function()
956
+ local controller = setup()
957
+ local tool, handle = controller.newTool()
958
+
959
+ expect(AdorneeUtils.getPart(tool)).toEqual(handle)
960
+
961
+ controller.destroy()
962
+ end)
963
+
964
+ it("returns nil for a tool with no handle", function()
965
+ local controller = setup()
966
+ local tool = controller.newHandlelessTool()
967
+
968
+ expect(AdorneeUtils.getPart(tool)).toBeNil()
969
+
970
+ controller.destroy()
971
+ end)
972
+
973
+ it("returns nil for an unsupported adornee", function()
974
+ local controller = setup()
975
+ local folder = controller.newFolder()
976
+
977
+ expect(AdorneeUtils.getPart(folder)).toBeNil()
978
+
979
+ controller.destroy()
980
+ end)
981
+
982
+ it("throws for a non-instance", function()
983
+ expect(function()
984
+ AdorneeUtils.getPart(nil :: any)
985
+ end).toThrow()
986
+ end)
987
+ end)
988
+
989
+ describe("AdorneeUtils.getRenderAdornee", function()
990
+ it("returns a base part itself", function()
991
+ local controller = setup()
992
+ local part = controller.newPart()
993
+
994
+ expect(AdorneeUtils.getRenderAdornee(part)).toEqual(part)
995
+
996
+ controller.destroy()
997
+ end)
998
+
999
+ it("returns a model itself", function()
1000
+ local controller = setup()
1001
+ local model = controller.newModel()
1002
+
1003
+ expect(AdorneeUtils.getRenderAdornee(model)).toEqual(model)
1004
+
1005
+ controller.destroy()
1006
+ end)
1007
+
1008
+ it("returns an attachment itself", function()
1009
+ local controller = setup()
1010
+ local part = controller.newPart()
1011
+ local attachment = controller.newAttachment(part)
1012
+
1013
+ expect(AdorneeUtils.getRenderAdornee(attachment)).toEqual(attachment)
1014
+
1015
+ controller.destroy()
1016
+ end)
1017
+
1018
+ it("returns the character of a humanoid", function()
1019
+ local controller = setup()
1020
+ local character, humanoid = controller.newCharacter()
1021
+
1022
+ expect(AdorneeUtils.getRenderAdornee(humanoid)).toEqual(character)
1023
+
1024
+ controller.destroy()
1025
+ end)
1026
+
1027
+ it("returns nil for a humanoid with no parent", function()
1028
+ local controller = setup()
1029
+ local humanoid = controller.newOrphanHumanoid()
1030
+
1031
+ expect(AdorneeUtils.getRenderAdornee(humanoid)).toBeNil()
1032
+
1033
+ controller.destroy()
1034
+ end)
1035
+
1036
+ it("returns the handle of an accessory", function()
1037
+ local controller = setup()
1038
+ local accessory, handle = controller.newAccessory()
1039
+
1040
+ expect(AdorneeUtils.getRenderAdornee(accessory)).toEqual(handle)
1041
+
1042
+ controller.destroy()
1043
+ end)
1044
+
1045
+ it("returns the part of clothing", function()
1046
+ local controller = setup()
1047
+ local clothing, part = controller.newClothing()
1048
+
1049
+ expect(AdorneeUtils.getRenderAdornee(clothing)).toEqual(part)
1050
+
1051
+ controller.destroy()
1052
+ end)
1053
+
1054
+ it("returns the handle of a tool rather than the tool", function()
1055
+ local controller = setup()
1056
+ local tool, handle = controller.newTool()
1057
+
1058
+ expect(AdorneeUtils.getRenderAdornee(tool)).toEqual(handle)
1059
+
1060
+ controller.destroy()
1061
+ end)
1062
+
1063
+ it("returns nil for a tool with no handle", function()
1064
+ local controller = setup()
1065
+ local tool = controller.newHandlelessTool()
1066
+
1067
+ expect(AdorneeUtils.getRenderAdornee(tool)).toBeNil()
1068
+
1069
+ controller.destroy()
1070
+ end)
1071
+
1072
+ it("returns nil for an unsupported adornee", function()
1073
+ local controller = setup()
1074
+ local folder = controller.newFolder()
1075
+
1076
+ expect(AdorneeUtils.getRenderAdornee(folder)).toBeNil()
1077
+
1078
+ controller.destroy()
1079
+ end)
1080
+
1081
+ it("throws for a non-instance", function()
1082
+ expect(function()
1083
+ AdorneeUtils.getRenderAdornee(nil :: any)
1084
+ end).toThrow()
1085
+ end)
1086
+ end)