local o=import("\046\047\071\097\109\101")local N=import("\046\047\070\111\108\100\101\114")local a=import("\046\046\047\102\117\110\099\116\105\111\110\115\047\116\121\112\101\111\102")local G=import("\046\047\066\097\115\101\073\110\115\116\097\110\099\101")describe("\105\110\115\116\097\110\099\101\115\046\066\097\115\101\073\110\115\116\097\110\099\101",function()it("\115\104\111\117\108\100 \101\114\114\111\114 \119\104\101\110 \112\097\114\101\110\116\105\110\103 \105\110\115\116\097\110\099\101\115 \116\111 \105\110\118\097\108\105\100 \111\098\106\101\099\116\115",function()local o=G:new()assert.has.errors(function()o.Parent=7 end)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \119\104\101\110 \115\101\116\116\105\110\103 \117\110\107\110\111\119\110 \118\097\108\117\101\115",function()local o=G:new()assert.has.errors(function()o.frobulations=6 end)end)it("\115\104\111\117\108\100 \101\114\114\111\114 \119\104\101\110 \105\110\100\101\120\105\110\103 \105\110\118\097\108\105\100 \105\110\115\116\097\110\099\101\115",function()local o=G:new()local function N() end assert.has.errors(function()N(o.neverWillEXIST)end)end)it("\115\104\111\117\108\100 \098\101 \105\100\101\110\116\105\102\105\101\100 \098\121 \116\121\112\101\111\102",function()local o=G:new()assert.equal(a(o),"\073\110\115\116\097\110\099\101")end)it("\115\104\111\117\108\100 \097\108\108\111\119 \116\104\101 \099\104\097\110\103\101 \097\110\100 \114\101\097\100 \111\102 \078\097\109\101",function()local o=G:new()assert.equal(o.Name,"\073\110\115\116\097\110\099\101")o.Name="\070\111\111\098\097\114"assert.equal(o.Name,"\070\111\111\098\097\114")end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \116\104\101 \099\104\097\110\103\101 \111\102 \067\108\097\115\115\078\097\109\101",function()local o=G:new()assert.has.errors(function()o.ClassName="\070\111\111\098\097\114"end)end)describe("\080\097\114\101\110\116",function()it("\115\104\111\117\108\100 \115\101\116 \116\111 \110\105\108",function()local o=G:new()local N=G:new()N.Parent=o N.Name="\102\111\111"assert.equal(o:FindFirstChild("\102\111\111"),N)N.Parent=nil assert.equal(o:FindFirstChild("\102\111\111"),nil)end)it("\115\104\111\117\108\100 \115\101\116 \116\111 \111\116\104\101\114 \105\110\115\116\097\110\099\101\115",function()local o=G:new()local N=G:new()local a=G:new()a.Parent=o a.Name="\102\111\111"assert.equal(o:FindFirstChild("\102\111\111"),a)a.Parent=N assert.equal(o:FindFirstChild("\102\111\111"),nil)assert.equal(a.Parent,N)assert.equal(N:FindFirstChild("\102\111\111"),a)end)it("\115\104\111\117\108\100\110\'\116 \114\101\097\099\116 \100\105\102\102\101\114\101\110\116\108\121 \119\104\101\110 \115\101\116\116\105\110\103 \116\104\101 \112\097\114\101\110\116 \116\111 \116\104\101 \101\120\105\115\116\105\110\103 \112\097\114\101\110\116",function()local o=G:new()local N=G:new()N.Parent=o assert.has_no_errors(function()N.Parent=o end)end)end)describe("\070\105\110\100\070\105\114\115\116\067\104\105\108\100",function()it("\115\104\111\117\108\100 \110\101\118\101\114 \101\114\114\111\114 \111\110 \105\110\118\097\108\105\100 \105\110\100\101\120",function()local o=G:new()assert.equal(o:FindFirstChild("\078\069\086\069\082\046 \087\073\076\076\046 \069\088\073\083\084\033"),nil)end)end)describe("\071\101\116\067\104\105\108\100\114\101\110",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\111 \099\104\105\108\100\114\101\110 \102\111\114 \101\109\112\116\121 \105\110\115\116\097\110\099\101\115",function()local o=G:new()assert.equal(#o:GetChildren(),0)end)it("\115\104\111\117\108\100 \121\105\101\108\100 \097\108\108 \099\104\105\108\100\114\101\110",function()local o=G:new()local N=G:new()N.Parent=o local a=G:new()a.Parent=o assert.equal(#o:GetChildren(),2)local i=false local w=false for o,G in ipairs(o:GetChildren())do if G==N then i=true elseif G==a then w=true else error("\073\110\118\097\108\105\100 \099\104\105\108\100 \102\111\117\110\100")end end assert.equal(i,true)assert.equal(w,true)end)end)describe("\071\101\116\068\101\115\099\101\110\100\097\110\116\115",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\111 \100\101\115\099\101\110\100\097\110\116\115 \102\111\114 \101\109\112\116\121 \105\110\115\116\097\110\099\101\115",function()local o=G:new()assert.equal(#o:GetDescendants(),0)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \097\108\108 \102\105\114\115\116 \108\101\118\101\108 \099\104\105\108\100\114\101\110",function()local o=G:new()local N=G:new()N.Parent=o local a=G:new()a.Parent=o assert.equal(#o:GetDescendants(),2)local i=false local w=false for o,G in ipairs(o:GetDescendants())do if G==N then i=true elseif G==a then w=true else error("\073\110\118\097\108\105\100 \099\104\105\108\100 \102\111\117\110\100")end end assert.equal(i,true)assert.equal(w,true)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \097\108\108 \100\101\115\099\101\110\100\097\110\116\115",function()local o=G:new()local N=G:new()N.Parent=o local a=G:new()a.Parent=o local i=G:new()i.Parent=a assert.equal(#o:GetDescendants(),3)local w=false local l=false local X=false for o,G in ipairs(o:GetDescendants())do if G==N then w=true elseif G==a then l=true elseif G==i then X=true else error("\073\110\118\097\108\105\100 \099\104\105\108\100 \102\111\117\110\100")end end assert.equal(w,true)assert.equal(l,true)assert.equal(X,true)end)end)describe("\087\097\105\116\070\111\114\067\104\105\108\100",function()it("\115\104\111\117\108\100 \119\111\114\107 \106\117\115\116 \108\105\107\101 \070\105\110\100\070\105\114\115\116\067\104\105\108\100",function()local o=G:new()local N=G:new()N.Parent=o N.Name="\102\111\111"local a=o:WaitForChild("\102\111\111")assert.equal(a,N)N.Parent=nil a=o:WaitForChild("\102\111\111")assert.equal(a,nil)end)end)describe("\068\101\115\116\114\111\121",function()it("\115\104\111\117\108\100 \115\101\116 \116\104\101 \105\110\115\116\097\110\099\101\'\115 \080\097\114\101\110\116 \116\111 \110\105\108",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(N.Parent,o)N:Destroy()assert.equal(N.Parent,nil)end)it("\115\104\111\117\108\100 \115\101\116 \116\104\101 \099\104\105\108\100\114\101\110\'\115 \112\097\114\101\110\116\115 \116\111 \110\105\108",function()local o=G:new()local N=G:new()N.Parent=o o:Destroy()assert.equal(N.Parent,nil)end)it("\115\104\111\117\108\100 \108\111\099\107 \116\104\101 \112\097\114\101\110\116 \112\114\111\112\101\114\116\121",function()local o=G:new()local N=G:new()o:Destroy()assert.has.errors(function()o.Parent=N end)end)it("\115\104\111\117\108\100 \111\110\108\121 \108\111\099\107 \105\116\115 \111\119\110 \105\110\115\116\097\110\099\101\044 \097\110\100 \110\111\116 \097\108\108 \111\102 \116\104\101 \115\097\109\101 \116\121\112\101",function()local o=G:new()o:Destroy()assert.equal(o.Parent,nil)local N=G:new()local a=G:new()assert.has_no.errors(function()a.Parent=N end)end)it("\115\104\111\117\108\100 \100\105\115\099\111\110\110\101\099\116 \097\108\108 \067\104\097\110\103\101\100 \108\105\115\116\101\110\101\114\115",function()local o=G:new()local N=0 o.Changed:Connect(function()N=N+1 end)o.Name="\070\111\111"assert.equal(N,1)o:Destroy()o.Name="\066\097\114"assert.equal(N,1)end)it("\115\104\111\117\108\100 \100\105\115\099\111\110\110\101\099\116 \097\108\108 \071\101\116\080\114\111\112\101\114\116\121\067\104\097\110\103\101\100\083\105\103\110\097\108 \108\105\115\116\101\110\101\114\115",function()local o=G:new()local N=0 local a=0;(o:GetPropertyChangedSignal("\078\097\109\101")):Connect(function()N=N+1 end);(o:GetPropertyChangedSignal("\078\097\109\101")):Connect(function()a=a+1 end)o.Name="\070\111\111"assert.equal(N,1)assert.equal(a,1)o:Destroy()o.Name="\066\097\114"assert.equal(N,1)assert.equal(a,1)end)end)describe("\073\115\065",function()it("\115\104\111\117\108\100 \099\104\101\099\107 \116\104\101 \099\108\097\115\115\'\115 \104\105\101\114\097\114\099\104\121",function()local o=G:extend("\067\108\097\115\115\065")local N=o:extend("\067\108\097\115\115\066")local a=N:extend("\067\108\097\115\115\067")local i=G:new()local w=o:new()local l=N:new()local X=a:new()assert.False(i:IsA("\067\108\097\115\115\067"))assert.False(i:IsA("\067\108\097\115\115\066"))assert.False(i:IsA("\067\108\097\115\115\065"))assert.True(i:IsA("\073\110\115\116\097\110\099\101"))assert.False(w:IsA("\067\108\097\115\115\067"))assert.False(w:IsA("\067\108\097\115\115\066"))assert.True(w:IsA("\067\108\097\115\115\065"))assert.True(w:IsA("\073\110\115\116\097\110\099\101"))assert.False(l:IsA("\067\108\097\115\115\067"))assert.True(l:IsA("\067\108\097\115\115\066"))assert.True(l:IsA("\067\108\097\115\115\065"))assert.True(l:IsA("\073\110\115\116\097\110\099\101"))assert.True(X:IsA("\067\108\097\115\115\067"))assert.True(X:IsA("\067\108\097\115\115\066"))assert.True(X:IsA("\067\108\097\115\115\065"))assert.True(X:IsA("\073\110\115\116\097\110\099\101"))end)end)describe("\073\115\068\101\115\099\101\110\100\097\110\116\079\102",function()it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\114\117\101 \119\104\101\110 \116\104\101 \105\110\115\116\097\110\099\101 \105\115 \097 \100\101\115\099\101\110\100\097\110\116 \111\102 \116\104\101 \112\097\115\115\101\100 \097\114\103\117\109\101\110\116",function()local o=G:new()local N=G:new()N.Parent=o assert.True(N:IsDescendantOf(o))local a=G:new()a.Parent=N assert.True(a:IsDescendantOf(o))end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \102\097\108\115\101 \119\104\101\110 \116\104\101 \105\110\115\116\097\110\099\101 \105\115 \110\111\116 \097 \100\101\115\099\101\110\100\097\110\116 \111\102 \116\104\101 \112\097\115\115\101\100 \097\114\103\117\109\101\110\116",function()local o=G:new()local N=G:new()assert.False(o:IsDescendantOf(N))local a=G:new()a.Parent=o assert.False(a:IsDescendantOf(N))local i=G:new()i.Parent=a assert.False(i:IsDescendantOf(N))end)it("\115\104\111\117\108\100 \097\108\119\097\121\115 \114\101\116\117\114\110 \116\114\117\101 \102\111\114 \110\105\108",function()assert.True((G:new()):IsDescendantOf(nil))end)end)describe("\071\101\116\070\117\108\108\078\097\109\101",function()it("\115\104\111\117\108\100 \103\101\116 \116\104\101 \102\117\108\108 \110\097\109\101",function()local o=G:new()o.Name="\084\101\115\116"local N=G:new()N.Name="\080\097\114\101\110\116"o.Parent=N local a=o:GetFullName()assert.equal("\080\097\114\101\110\116\046\084\101\115\116",a)end)it("\115\104\111\117\108\100 \101\120\099\108\117\100\101 \103\097\109\101",function()local N=G:new()N.Name="\084\101\115\116"local a=o:new()a.Name="\080\097\114\101\110\116"N.Parent=a local i=N:GetFullName()assert.equal("\084\101\115\116",i)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \116\104\101 \105\110\115\116\097\110\099\101 \110\097\109\101 \105\102 \116\104\101\114\101 \105\115 \110\111 \112\097\114\101\110\116",function()local o=G:new()o.Name="\084\101\115\116"local N=o:GetFullName()assert.equal("\084\101\115\116",N)end)end)describe("\116\111\115\116\114\105\110\103",function()it("\115\104\111\117\108\100 \109\097\116\099\104 \116\104\101 \110\097\109\101 \111\102 \116\104\101 \105\110\115\116\097\110\099\101",function()local o=G:new()o.Name="\102\111\111"assert.equal(tostring(o),"\102\111\111")end)end)describe("\067\104\097\110\103\101\100",function()it("\115\104\111\117\108\100 \102\105\114\101 \067\104\097\110\103\101\100",function()local o=G:new()local N=spy.new(function() end)o.Changed:Connect(N)o.Name="\078\097\109\101\067\104\097\110\103\101";(assert.spy(N)).was.called_with("\078\097\109\101")end)end)describe("\071\101\116\080\114\111\112\101\114\116\121\067\104\097\110\103\101\100\083\105\103\110\097\108",function()it("\115\104\111\117\108\100 \102\105\114\101 \112\114\111\112\101\114\116\121 \115\105\103\110\097\108\115 \102\111\114 \116\104\101 \114\105\103\104\116 \112\114\111\112\101\114\116\121",function()local o=G:new()local N=spy.new(function() end);(o:GetPropertyChangedSignal("\078\097\109\101")):Connect(N)o.Name="\078\097\109\101\067\104\097\110\103\101";(assert.spy(N)).was.called()end)it("\115\104\111\117\108\100 \110\111\116 \102\105\114\101 \112\114\111\112\101\114\116\121 \115\105\103\110\097\108\115 \102\111\114 \116\104\101 \105\110\099\111\114\114\101\099\116 \112\114\111\112\101\114\116\121",function()local o=G:new()local N=spy.new(function() end);(o:GetPropertyChangedSignal("\080\097\114\101\110\116")):Connect(N)o.Name="\078\097\109\101\067\104\097\110\103\101\050";(assert.spy(N)).was_not_called()end)it("\115\104\111\117\108\100 \101\114\114\111\114 \119\104\101\110 \103\105\118\101\110 \097\110 \105\110\118\097\108\105\100 \112\114\111\112\101\114\116\121 \110\097\109\101",function()local o=G:new()assert.has.errors(function()(o:GetPropertyChangedSignal("\067\097\110\068\101\115\116\114\111\121\084\104\101\087\111\114\108\100")):Connect(function() end)end)end)end)describe("\067\108\101\097\114\065\108\108\067\104\105\108\100\114\101\110",function()it("\115\104\111\117\108\100 \099\108\101\097\114 \099\104\105\108\100\114\101\110",function()local o=G:new()local N=G:new()N.Parent=o o:ClearAllChildren()assert.equal(N.Parent,nil)end)end)describe("\070\105\110\100\070\105\114\115\116\065\110\099\101\115\116\111\114",function()it("\115\104\111\117\108\100 \102\105\110\100 \097\110\099\101\115\116\111\114\115",function()local o=G:new()o.Name="\065\110\099\101\115\116\111\114"local N=G:new()N.Parent=o assert.equal(N:FindFirstAncestor("\065\110\099\101\115\116\111\114"),o)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \109\097\116\099\104\105\110\103 \097\110\099\101\115\116\111\114",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(N:FindFirstAncestor("\065\110\099\101\115\116\111\114"),nil)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \097\110\099\101\115\116\111\114",function()local o=G:new()assert.equal(o:FindFirstAncestor("\065\110\099\101\115\116\111\114"),nil)end)end)describe("\070\105\110\100\070\105\114\115\116\065\110\099\101\115\116\111\114\079\102\067\108\097\115\115",function()it("\115\104\111\117\108\100 \102\105\110\100 \097\110\099\101\115\116\111\114\115",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(N:FindFirstAncestorOfClass("\073\110\115\116\097\110\099\101"),o)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \109\097\116\099\104\105\110\103 \097\110\099\101\115\116\111\114",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(N:FindFirstAncestorOfClass("\065\110\099\101\115\116\111\114"),nil)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \097\110\099\101\115\116\111\114",function()local o=G:new()assert.equal(o:FindFirstAncestorOfClass("\073\110\115\116\097\110\099\101"),nil)end)end)describe("\070\105\110\100\070\105\114\115\116\065\110\099\101\115\116\111\114\087\104\105\099\104\073\115\065",function()it("\115\104\111\117\108\100 \102\105\110\100 \097\110\099\101\115\116\111\114\115",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(N:FindFirstAncestorOfClass("\073\110\115\116\097\110\099\101"),o)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \109\097\116\099\104\105\110\103 \097\110\099\101\115\116\111\114",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(N:FindFirstAncestorOfClass("\065\110\099\101\115\116\111\114"),nil)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \097\110\099\101\115\116\111\114",function()local o=G:new()assert.equal(o:FindFirstAncestorOfClass("\073\110\115\116\097\110\099\101"),nil)end)it("\115\104\111\117\108\100 \104\097\110\100\108\101 \110\097\114\114\111\119\101\114 \097\110\099\101\115\116\111\114 \099\108\097\115\115\101\115",function()local o=G:new()local a=N:new()o.Parent=a assert.equal(o:FindFirstAncestorWhichIsA("\073\110\115\116\097\110\099\101"),a)end)end)describe("\070\105\110\100\070\105\114\115\116\067\104\105\108\100\079\102\067\108\097\115\115",function()it("\115\104\111\117\108\100 \102\105\110\100 \105\110\115\116\097\110\099\101\115",function()local o=G:new()local a=G:new()a.Parent=o local i=N:new()i.Parent=o assert.equal(o:FindFirstChildOfClass("\073\110\115\116\097\110\099\101"),a)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \109\097\116\099\104\105\110\103 \099\104\105\108\100",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(o:FindFirstChildOfClass("\070\111\108\100\101\114"),nil)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \099\104\105\108\100\114\101\110",function()local o=G:new()assert.equal(o:FindFirstChildOfClass("\070\111\108\100\101\114"),nil)end)end)describe("\070\105\110\100\070\105\114\115\116\067\104\105\108\100\079\102\067\108\097\115\115",function()it("\115\104\111\117\108\100 \102\105\110\100 \105\110\115\116\097\110\099\101\115",function()local o=G:new()local a=G:new()a.Parent=o local i=N:new()i.Parent=o assert.equal(o:FindFirstChildWhichIsA("\073\110\115\116\097\110\099\101"),a)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \109\097\116\099\104\105\110\103 \099\104\105\108\100",function()local o=G:new()local N=G:new()N.Parent=o assert.equal(o:FindFirstChildWhichIsA("\070\111\108\100\101\114"),nil)end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \110\105\108 \119\105\116\104 \110\111 \099\104\105\108\100\114\101\110",function()local o=G:new()assert.equal(o:FindFirstChildWhichIsA("\070\111\108\100\101\114"),nil)end)end)describe("\115\117\112\101\114",function()it("\115\104\111\117\108\100 \114\101\102\101\114\101\110\099\101 \116\104\101 \112\097\114\101\110\116 \099\108\097\115\115",function()local o=G:extend("\067\108\097\115\115\065")local N=o:extend("\067\108\097\115\115\066")local a=N:extend("\067\108\097\115\115\067")assert.equals(a.super,N)assert.equals(N.super,o)assert.equals(o.super,G)assert.equals(G.super,nil)end)end)describe("\065\110\099\101\115\116\114\121\067\104\097\110\103\101\100",function()it("\115\104\111\117\108\100 \102\105\114\101 \119\104\101\110 \109\121 \112\097\114\101\110\116 \099\104\097\110\103\101\115",function()local o=G:new()local N=spy.new(function() end)o.AncestryChanged:Connect(N)local a=G:new()local i=spy.new(function() end)a.AncestryChanged:Connect(i)a.Parent=o;(assert.spy(N)).was_not_called();(assert.spy(i)).was_called_with(a,o)a.Parent=nil;(assert.spy(N)).was_not_called();(assert.spy(i)).was_called_with(a,nil)end)it("\115\104\111\117\108\100 \102\105\114\101 \119\104\101\110 \109\121 \097\110\099\101\115\116\111\114 \099\104\097\110\103\101\115",function()local o=G:new()local N=spy.new(function() end)o.AncestryChanged:Connect(N)local a=G:new()local i=spy.new(function() end)a.AncestryChanged:Connect(i)local w=G:new()local l=spy.new(function() end)w.AncestryChanged:Connect(l)w.Parent=a;(assert.spy(N)).was_not_called();(assert.spy(i)).was_not_called();(assert.spy(l)).was_called_with(w,a)N:clear()i:clear()l:clear()a.Parent=o;(assert.spy(N)).was_not_called();(assert.spy(i)).was_called_with(a,o);(assert.spy(l)).was_called_with(a,o)N:clear()i:clear()l:clear()a.Parent=nil;(assert.spy(N)).was_not_called();(assert.spy(i)).was_called_with(a,nil);(assert.spy(l)).was_called_with(a,nil)N:clear()i:clear()l:clear()w.Parent=nil;(assert.spy(N)).was_not_called();(assert.spy(i)).was_not_called();(assert.spy(l)).was_called_with(w,nil)end)end)describe("\067\104\105\108\100\065\100\100\101\100",function()it("\115\104\111\117\108\100 \102\105\114\101 \119\104\101\110 \097 \099\104\105\108\100 \105\115 \097\100\100\101\100",function()local o=G:new()local N=G:new()local a=spy.new(function() end)o.ChildAdded:Connect(a)N.Parent=o;(assert.spy(a)).was_called_with(N)end)end)describe("\067\104\105\108\100\082\101\109\111\118\101\100",function()it("\115\104\111\117\108\100 \102\105\114\101 \119\104\101\110 \097 \099\104\105\108\100 \105\115 \114\101\109\111\118\101\100",function()local o=G:new()local N=G:new()N.Parent=o local a=spy.new(function() end)o.ChildRemoved:Connect(a)N.Parent=nil;(assert.spy(a)).was_called_with(N)end)end)end)
local Game = import("./Game")
local Folder = import("./Folder")
local typeof = import("../functions/typeof")

local BaseInstance = import("./BaseInstance")

describe("instances.BaseInstance", function()
	it("should error when parenting instances to invalid objects", function()
		local new = BaseInstance:new()

		assert.has.errors(function()
			new.Parent = 7
		end)
	end)

	it("should error when setting unknown values", function()
		local new = BaseInstance:new()

		assert.has.errors(function()
			new.frobulations = 6
		end)
	end)

	it("should error when indexing invalid instances", function()
		local instance = BaseInstance:new()

		local function nop()
		end

		assert.has.errors(function()
			nop(instance.neverWillEXIST)
		end)
	end)

	it("should be identified by typeof", function()
		local instance = BaseInstance:new()

		assert.equal(typeof(instance), "Instance")
	end)

	it("should allow the change and read of Name", function()
		local instance = BaseInstance:new()
		assert.equal(instance.Name, "Instance")

		instance.Name = "Foobar"
		assert.equal(instance.Name, "Foobar")
	end)

	it("should not allow the change of ClassName", function()
		local instance = BaseInstance:new()

		assert.has.errors(function()
			instance.ClassName = "Foobar"
		end)
	end)

	describe("Parent", function()
		it("should set to nil", function()
			local parent = BaseInstance:new()

			local child = BaseInstance:new()
			child.Parent = parent
			child.Name = "foo"

			assert.equal(parent:FindFirstChild("foo"), child)

			child.Parent = nil

			assert.equal(parent:FindFirstChild("foo"), nil)
		end)

		it("should set to other instances", function()
			local parent1 = BaseInstance:new()
			local parent2 = BaseInstance:new()

			local child = BaseInstance:new()
			child.Parent = parent1
			child.Name = "foo"

			assert.equal(parent1:FindFirstChild("foo"), child)

			child.Parent = parent2

			assert.equal(parent1:FindFirstChild("foo"), nil)
			assert.equal(child.Parent, parent2)
			assert.equal(parent2:FindFirstChild("foo"), child)
		end)

		-- This may seem like a weird test, but it's for 100% coverage
		it("shouldn't react differently when setting the parent to the existing parent", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			assert.has_no_errors(function()
				child.Parent = parent
			end)
		end)
	end)

	describe("FindFirstChild", function()
		it("should never error on invalid index", function()
			local instance = BaseInstance:new()

			assert.equal(instance:FindFirstChild("NEVER. WILL. EXIST!"), nil)
		end)
	end)

	describe("GetChildren", function()
		it("should return no children for empty instances", function()
			local instance = BaseInstance:new()

			assert.equal(#instance:GetChildren(), 0)
		end)

		it("should yield all children", function()
			local parent = BaseInstance:new()

			local child1 = BaseInstance:new()
			child1.Parent = parent

			local child2 = BaseInstance:new()
			child2.Parent = parent

			assert.equal(#parent:GetChildren(), 2)

			local child1Seen = false
			local child2Seen = false
			for _, child in ipairs(parent:GetChildren()) do
				if child == child1 then
					child1Seen = true
				elseif child == child2 then
					child2Seen = true
				else
					error("Invalid child found")
				end
			end

			assert.equal(child1Seen, true)
			assert.equal(child2Seen, true)
		end)
	end)

	describe("GetDescendants", function()
		it("should return no descendants for empty instances", function()
			local instance = BaseInstance:new()

			assert.equal(#instance:GetDescendants(), 0)
		end)

		it("should return all first level children", function()
			local parent = BaseInstance:new()

			local child1 = BaseInstance:new()
			child1.Parent = parent

			local child2 = BaseInstance:new()
			child2.Parent = parent

			assert.equal(#parent:GetDescendants(), 2)

			local child1Seen = false
			local child2Seen = false
			for _, child in ipairs(parent:GetDescendants()) do
				if child == child1 then
					child1Seen = true
				elseif child == child2 then
					child2Seen = true
				else
					error("Invalid child found")
				end
			end

			assert.equal(child1Seen, true)
			assert.equal(child2Seen, true)
		end)

		it("should return all descendants", function()
			local parent = BaseInstance:new()

			local child1 = BaseInstance:new()
			child1.Parent = parent

			local child2 = BaseInstance:new()
			child2.Parent = parent

			local child3 = BaseInstance:new()
			child3.Parent = child2

			assert.equal(#parent:GetDescendants(), 3)

			local child1Seen = false
			local child2Seen = false
			local child3Seen = false
			for _, child in ipairs(parent:GetDescendants()) do
				if child == child1 then
					child1Seen = true
				elseif child == child2 then
					child2Seen = true
				elseif child == child3 then
					child3Seen = true
				else
					error("Invalid child found")
				end
			end

			assert.equal(child1Seen, true)
			assert.equal(child2Seen, true)
			assert.equal(child3Seen, true)
		end)
	end)

	describe("WaitForChild", function()
		it("should work just like FindFirstChild", function()
			local parent = BaseInstance:new()

			local child = BaseInstance:new()
			child.Parent = parent
			child.Name = "foo"

			local result = parent:WaitForChild("foo")
			assert.equal(result, child)

			child.Parent = nil
			result = parent:WaitForChild("foo")
			assert.equal(result, nil)
		end)
	end)

	describe("Destroy", function()
		it("should set the instance's Parent to nil", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			assert.equal(child.Parent, parent)

			child:Destroy()

			assert.equal(child.Parent, nil)
		end)

		it("should set the children's parents to nil", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			parent:Destroy()
			assert.equal(child.Parent, nil)
		end)

		it("should lock the parent property", function()
			local instance = BaseInstance:new()
			local badParent = BaseInstance:new()

			instance:Destroy()

			assert.has.errors(function()
				instance.Parent = badParent
			end)
		end)

		it("should only lock its own instance, and not all of the same type", function()
			local destroyFolder = BaseInstance:new()
			destroyFolder:Destroy()
			assert.equal(destroyFolder.Parent, nil)

			local goodParent = BaseInstance:new()
			local goodFolder = BaseInstance:new()

			assert.has_no.errors(function()
				goodFolder.Parent = goodParent
			end)
		end)

		it("should disconnect all Changed listeners", function()
			local instance = BaseInstance:new()

			local calls = 0
			instance.Changed:Connect(function()
				calls = calls + 1
			end)

			instance.Name = "Foo"

			assert.equal(calls, 1)

			instance:Destroy()
			instance.Name = "Bar"

			assert.equal(calls, 1)
		end)

		it("should disconnect all GetPropertyChangedSignal listeners", function()
			local instance = BaseInstance:new()

			local callsA = 0
			local callsB = 0

			instance:GetPropertyChangedSignal("Name"):Connect(function()
				callsA = callsA + 1
			end)

			instance:GetPropertyChangedSignal("Name"):Connect(function()
				callsB = callsB + 1
			end)

			instance.Name = "Foo"

			assert.equal(callsA, 1)
			assert.equal(callsB, 1)

			instance:Destroy()
			instance.Name = "Bar"

			assert.equal(callsA, 1)
			assert.equal(callsB, 1)
		end)
	end)

	describe("IsA", function()
		it("should check the class's hierarchy", function()
			local ClassA = BaseInstance:extend("ClassA")
			local ClassB = ClassA:extend("ClassB")
			local ClassC = ClassB:extend("ClassC")

			local instance = BaseInstance:new()
			local objA = ClassA:new()
			local objB = ClassB:new()
			local objC = ClassC:new()

			assert.False(instance:IsA("ClassC"))
			assert.False(instance:IsA("ClassB"))
			assert.False(instance:IsA("ClassA"))
			assert.True(instance:IsA("Instance"))

			assert.False(objA:IsA("ClassC"))
			assert.False(objA:IsA("ClassB"))
			assert.True(objA:IsA("ClassA"))
			assert.True(objA:IsA("Instance"))

			assert.False(objB:IsA("ClassC"))
			assert.True(objB:IsA("ClassB"))
			assert.True(objB:IsA("ClassA"))
			assert.True(objB:IsA("Instance"))

			assert.True(objC:IsA("ClassC"))
			assert.True(objC:IsA("ClassB"))
			assert.True(objC:IsA("ClassA"))
			assert.True(objC:IsA("Instance"))
		end)
	end)

	describe("IsDescendantOf", function()
		it("should return true when the instance is a descendant of the passed argument", function()
			local parent = BaseInstance:new()

			local child = BaseInstance:new()
			child.Parent = parent
			assert.True(child:IsDescendantOf(parent))

			local descendant = BaseInstance:new()
			descendant.Parent = child
			assert.True(descendant:IsDescendantOf(parent))
		end)

		it("should return false when the instance is not a descendant of the passed argument", function()
			local parent = BaseInstance:new()
			local somethingElse = BaseInstance:new()
			assert.False(parent:IsDescendantOf(somethingElse))

			local child = BaseInstance:new()
			child.Parent = parent
			assert.False(child:IsDescendantOf(somethingElse))

			local descendant = BaseInstance:new()
			descendant.Parent = child
			assert.False(descendant:IsDescendantOf(somethingElse))
		end)

		-- Weird, but documented, behavior (https://www.robloxdev.com/api-reference/function/Instance/IsDescendantOf).
		it("should always return true for nil", function()
			assert.True(BaseInstance:new():IsDescendantOf(nil))
		end)
	end)

	describe("GetFullName", function()
		it("should get the full name", function()
			local instance = BaseInstance:new()
			instance.Name = "Test"
			local other = BaseInstance:new()
			other.Name = "Parent"

			instance.Parent = other

			local fullName = instance:GetFullName()
			assert.equal("Parent.Test", fullName)
		end)

		it("should exclude game", function()
			local instance = BaseInstance:new()
			instance.Name = "Test"
			local other = Game:new()
			other.Name = "Parent"

			instance.Parent = other

			local fullName = instance:GetFullName()
			assert.equal("Test", fullName)
		end)

		it("should return the instance name if there is no parent", function()
			local instance = BaseInstance:new()
			instance.Name = "Test"

			local fullName = instance:GetFullName()
			assert.equal("Test", fullName)
		end)
	end)

	describe("tostring", function()
		it("should match the name of the instance", function()
			local instance = BaseInstance:new()
			instance.Name = "foo"

			assert.equal(tostring(instance), "foo")
		end)
	end)

	describe("Changed", function()
		it("should fire Changed", function()
			local instance = BaseInstance:new()

			local changedSpy = spy.new(function() end)
			instance.Changed:Connect(changedSpy)

			instance.Name = "NameChange"
			assert.spy(changedSpy).was.called_with("Name")
		end)
	end)

	describe("GetPropertyChangedSignal", function()
		it("should fire property signals for the right property", function()
			local instance = BaseInstance:new()
			local spy = spy.new(function() end)
			instance:GetPropertyChangedSignal("Name"):Connect(spy)
			instance.Name = "NameChange"
			assert.spy(spy).was.called()
		end)

		it("should not fire property signals for the incorrect property", function()
			local instance = BaseInstance:new()
			local spy = spy.new(function() end)
			instance:GetPropertyChangedSignal("Parent"):Connect(spy)
			instance.Name = "NameChange2"
			assert.spy(spy).was_not_called()
		end)

		it("should error when given an invalid property name", function()
			local instance = BaseInstance:new()
			assert.has.errors(function()
				instance:GetPropertyChangedSignal("CanDestroyTheWorld"):Connect(function() end)
			end)
		end)
	end)

	describe("ClearAllChildren", function()
		it("should clear children", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			parent:ClearAllChildren()
			assert.equal(child.Parent, nil)
		end)
	end)

	describe("FindFirstAncestor", function()
		it("should find ancestors", function()
			local parent = BaseInstance:new()
			parent.Name = "Ancestor"

			local child = BaseInstance:new()
			child.Parent = parent

			assert.equal(child:FindFirstAncestor("Ancestor"), parent)
		end)

		it("should return nil with no matching ancestor", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			assert.equal(child:FindFirstAncestor("Ancestor"), nil)
		end)

		it("should return nil with no ancestor", function()
			local child = BaseInstance:new()

			assert.equal(child:FindFirstAncestor("Ancestor"), nil)
		end)
	end)

	describe("FindFirstAncestorOfClass", function()
		it("should find ancestors", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			assert.equal(child:FindFirstAncestorOfClass("Instance"), parent)
		end)

		it("should return nil with no matching ancestor", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			assert.equal(child:FindFirstAncestorOfClass("Ancestor"), nil)
		end)

		it("should return nil with no ancestor", function()
			local child = BaseInstance:new()

			assert.equal(child:FindFirstAncestorOfClass("Instance"), nil)
		end)
	end)

	describe("FindFirstAncestorWhichIsA", function()
		it("should find ancestors", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			assert.equal(child:FindFirstAncestorOfClass("Instance"), parent)
		end)

		it("should return nil with no matching ancestor", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			assert.equal(child:FindFirstAncestorOfClass("Ancestor"), nil)
		end)

		it("should return nil with no ancestor", function()
			local child = BaseInstance:new()

			assert.equal(child:FindFirstAncestorOfClass("Instance"), nil)
		end)

		it("should handle narrower ancestor classes", function()
			local child = BaseInstance:new()
			local parent = Folder:new()
			child.Parent = parent

			assert.equal(child:FindFirstAncestorWhichIsA("Instance"), parent)
		end)
	end)

	describe("FindFirstChildOfClass", function()
		it("should find instances", function()
			local parent = BaseInstance:new()
			local childCorrect = BaseInstance:new()
			childCorrect.Parent = parent

			local childIncorrect = Folder:new()
			childIncorrect.Parent = parent

			assert.equal(parent:FindFirstChildOfClass("Instance"), childCorrect)
		end)

		it("should return nil with no matching child", function()
			local parent = BaseInstance:new()

			local childIncorrect = BaseInstance:new()
			childIncorrect.Parent = parent

			assert.equal(parent:FindFirstChildOfClass("Folder"), nil)
		end)

		it("should return nil with no children", function()
			local parent = BaseInstance:new()

			assert.equal(parent:FindFirstChildOfClass("Folder"), nil)
		end)
	end)

	describe("FindFirstChildOfClass", function()
		it("should find instances", function()
			local parent = BaseInstance:new()
			local childCorrect = BaseInstance:new()
			childCorrect.Parent = parent

			local childIncorrect = Folder:new()
			childIncorrect.Parent = parent

			assert.equal(parent:FindFirstChildWhichIsA("Instance"), childCorrect)
		end)

		it("should return nil with no matching child", function()
			local parent = BaseInstance:new()

			local childIncorrect = BaseInstance:new()
			childIncorrect.Parent = parent

			assert.equal(parent:FindFirstChildWhichIsA("Folder"), nil)
		end)

		it("should return nil with no children", function()
			local parent = BaseInstance:new()

			assert.equal(parent:FindFirstChildWhichIsA("Folder"), nil)
		end)
	end)

	describe("super", function()
		it("should reference the parent class", function()
			local ClassA = BaseInstance:extend("ClassA")
			local ClassB = ClassA:extend("ClassB")
			local ClassC = ClassB:extend("ClassC")

			assert.equals(ClassC.super, ClassB)
			assert.equals(ClassB.super, ClassA)
			assert.equals(ClassA.super, BaseInstance)
			assert.equals(BaseInstance.super, nil)
		end)
	end)

	describe("AncestryChanged", function()
		it("should fire when my parent changes", function()
			local parent = BaseInstance:new()
			local parentSpy = spy.new(function() end)
			parent.AncestryChanged:Connect(parentSpy)

			local child = BaseInstance:new()
			local childSpy = spy.new(function() end)
			child.AncestryChanged:Connect(childSpy)

			child.Parent = parent
			assert.spy(parentSpy).was_not_called()
			assert.spy(childSpy).was_called_with(child, parent)

			child.Parent = nil
			assert.spy(parentSpy).was_not_called()
			assert.spy(childSpy).was_called_with(child, nil)
		end)

		it("should fire when my ancestor changes", function()
			local parent = BaseInstance:new()
			local parentSpy = spy.new(function() end)
			parent.AncestryChanged:Connect(parentSpy)

			local child = BaseInstance:new()
			local childSpy = spy.new(function() end)
			child.AncestryChanged:Connect(childSpy)

			local grandchild = BaseInstance:new()
			local grandchildSpy = spy.new(function() end)
			grandchild.AncestryChanged:Connect(grandchildSpy)

			grandchild.Parent = child
			assert.spy(parentSpy).was_not_called()
			assert.spy(childSpy).was_not_called()
			assert.spy(grandchildSpy).was_called_with(grandchild, child)

			parentSpy:clear()
			childSpy:clear()
			grandchildSpy:clear()

			child.Parent = parent
			assert.spy(parentSpy).was_not_called()
			assert.spy(childSpy).was_called_with(child, parent)
			assert.spy(grandchildSpy).was_called_with(child, parent)

			parentSpy:clear()
			childSpy:clear()
			grandchildSpy:clear()

			child.Parent = nil
			assert.spy(parentSpy).was_not_called()
			assert.spy(childSpy).was_called_with(child, nil)
			assert.spy(grandchildSpy).was_called_with(child, nil)

			parentSpy:clear()
			childSpy:clear()
			grandchildSpy:clear()

			grandchild.Parent = nil
			assert.spy(parentSpy).was_not_called()
			assert.spy(childSpy).was_not_called()
			assert.spy(grandchildSpy).was_called_with(grandchild, nil)
		end)
	end)

	describe("ChildAdded", function()
		it("should fire when a child is added", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()

			local spy = spy.new(function() end)
			parent.ChildAdded:Connect(spy)

			child.Parent = parent
			assert.spy(spy).was_called_with(child)
		end)
	end)

	describe("ChildRemoved", function()
		it("should fire when a child is removed", function()
			local parent = BaseInstance:new()
			local child = BaseInstance:new()
			child.Parent = parent

			local spy = spy.new(function() end)
			parent.ChildRemoved:Connect(spy)

			child.Parent = nil

			assert.spy(spy).was_called_with(child)
		end)
	end)
end)