return function()local K=require(script.Parent.Object)local M=K:Extend("\084\101\115\116\067\108\097\115\115")function M.constructor(K) end describe("\067\108\097\115\115\101\115",function()it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \099\114\101\097\116\101 \097 \099\108\097\115\115",function()local K=M.new();(expect(K)).to.be.ok();(expect(M:Is(K))).to.equal(true);(expect(K:IsType("\084\101\115\116\067\108\097\115\115"))).to.equal(true)end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \099\114\101\097\116\105\110\103 \097\110 \111\098\106\101\099\116 \102\114\111\109 \097\110\111\116\104\101\114 \111\098\106\101\099\116",function()(expect(function()local K=M.new()K.new()end)).to.throw()end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \104\097\110\100\108\101 \111\098\106\101\099\116 \105\110\104\101\114\105\116\097\110\099\101",function()local K=M:Extend("\084\101\115\116\067\108\097\115\115\050")function K.constructor(K)M:super(K)end local D=K.new();(expect(D)).to.be.ok();(expect(M:Is(D))).to.equal(true);(expect(D:IsType("\084\101\115\116\067\108\097\115\115\050"))).to.equal(true);(expect(D:IsType("\084\101\115\116\067\108\097\115\115"))).to.equal(true)end)it("\115\104\111\117\108\100 \112\097\115\115 \097\114\103\117\109\101\110\116\115 \102\114\111\109 \110\101\119 \116\111 \099\111\110\115\116\114\117\099\116\111\114",function()local M=K:Extend("\084\101\115\116\067\108\097\115\115\051")function M.constructor(M,K)M.value=K end local D=M.new("\072\101\108\108\111\044 \087\111\114\108\100");(expect(D.value)).to.equal("\072\101\108\108\111\044 \087\111\114\108\100")end)it("\115\104\111\117\108\100 \112\097\115\115 \097\114\103\117\109\101\110\116\115 \116\111 \098\097\115\101 \099\111\110\115\116\114\117\099\116\111\114\115 \116\104\114\111\117\103\104 \115\117\112\101\114",function()local M=K:Extend("\084\101\115\116\067\108\097\115\115\052")function M.constructor(M,K)M.a=K end local D=M:Extend("\084\101\115\116\067\108\097\115\115\053")function D.constructor(b,K,D)M:super(b,K)b.b=D end local b=D.new("\072\101\108\108\111","\087\111\114\108\100");(expect(b.a)).to.equal("\072\101\108\108\111");(expect(b.b)).to.equal("\087\111\114\108\100")end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \099\114\101\097\116\105\111\110 \111\102 \097\098\115\116\114\097\099\116 \111\098\106\101\099\116\115",function()local M=K:Extend("\065\098\115\116\114\097\099\116\067\108\097\115\115",{abstract=true});(expect(function()M.new()end)).to.throw()end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \100\117\112\108\105\099\097\116\101 \099\108\097\115\115 \110\097\109\101\115",function()K:Extend("\068\117\112\108\105\099\097\116\101\067\108\097\115\115");(expect(function()K:Extend("\068\117\112\108\105\099\097\116\101\067\108\097\115\115")end)).to.throw()end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \101\120\116\101\110\115\105\111\110 \111\102 \115\101\097\108\101\100 \099\108\097\115\115\101\115",function()local M=K:Extend("\083\101\097\108\101\100\067\108\097\115\115",{sealed=true});(expect(function()M:Extend("\083\117\098\083\101\097\108\101\100\067\108\097\115\115")end)).to.throw()end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \097\110 \097\098\115\116\114\097\099\116 \115\101\097\108\101\100 \099\108\097\115\115",function()(expect(function()K:Extend("\083\101\097\108\101\100\065\098\115\116\114\097\099\116\067\108\097\115\115",{sealed=true,abstract=true})end)).to.throw()end)it("\115\104\111\117\108\100 \115\117\112\112\111\114\116 \099\108\097\115\115\046\105\110\115\116\097\110\099\101",function()local K=M.new();(expect(M.instance(K))).to.equal(true);(expect(M.instance(setmetatable({},{})))).to.equal(false);(expect(M.instance(M))).to.equal(false);(expect(M.instance(10))).to.equal(false)end)describe("\077\101\116\104\111\100\115",function()it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \099\097\108\108\105\110\103 \073\115\084\121\112\101 \111\110 \099\108\097\115\115\101\115",function()(expect(function()M:IsType(M)end)).to.throw()end)it("\115\104\111\117\108\100 \114\101\116\117\114\110 \102\097\108\115\101 \111\110 \110\111\110-\109\097\116\099\104\105\110\103 \105\115\084\121\112\101 \099\108\097\115\115\078\097\109\101\115",function()local K=M.new();(expect(K:IsType("\078\111\112\101"))).to.equal(false)end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \099\097\108\108\105\110\103 \073\115 \111\110 \105\110\115\116\097\110\099\101\115",function()(expect(function()local K=M.new()K:Is("\084\101\115\116\067\108\097\115\115")end)).to.throw()end)end)end)describe("\079\098\106\101\099\116\070\097\099\116\111\114\121",function()it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \097\115\115\105\103\110\105\110\103 \097 \118\097\108\117\101 \116\111 \079\098\106\101\099\116\070\097\099\116\111\114\121",function()(expect(function()K.test=10 end)).to.throw()end)end)describe("\069\110\117\109\115",function()it("\115\104\111\117\108\100 \104\097\110\100\108\101 \101\110\117\109 \099\114\101\097\116\105\111\110",function()local M=K:Enum("\084\101\115\116\069\110\117\109",{"\084\101\115\116\086\097\108\117\101\065";"\084\101\115\116\086\097\108\117\101\066"});(expect(M)).to.be.ok();(expect(M:Is(M.TestValueA))).to.equal(true);(expect(M:Is(M.TestValueB))).to.equal(true);(expect(M.TestValueA.Value)).to.equal(1);(expect(M.TestValueB.Value)).to.equal(2);(expect(M.TestValueA.Name)).to.equal("\084\101\115\116\086\097\108\117\101\065");(expect(M.TestValueB.Name)).to.equal("\084\101\115\116\086\097\108\117\101\066");(expect(tostring(M.TestValueA))).to.equal("\069\110\117\109\091\084\101\115\116\069\110\117\109\064\084\101\115\116\086\097\108\117\101\065\093")end)end)describe("\068\101\115\116\114\111\121",function()it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \100\101\115\116\114\111\121 \111\098\106\101\099\116\115",function()local M=K:Extend("\084\101\115\116\068\101\115\116\114\111\121\101\100\067\108\097\115\115")function M.constructor(K)K._test=10 end function M.destructor(K) end local D=M.new()D:Destroy();(expect(tostring(D))).to.equal("\068\101\115\116\114\111\121\101\100\079\098\106\101\099\116");(expect(function()print(D._test)end)).to.throw();(expect(function()D._test=10 end)).to.throw()end)it("\115\104\111\117\108\100 \110\111\116 \097\108\108\111\119 \100\101\115\116\114\111\121\105\110\103 \099\108\097\115\115\101\115 \111\114 \079\098\106\101\099\116\070\097\099\116\111\114\121",function()(expect(function()K:Destroy()end)).to.throw();(expect(function()M:Destroy()end)).to.throw()end)end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \103\101\116 \099\108\097\115\115\101\115 \119\105\116\104 \071\101\116\040\041",function()local M=K:Get("\084\101\115\116\067\108\097\115\115");(expect(M)).to.be.ok()end)it("\115\104\111\117\108\100 \101\114\114\111\114 \111\110 \105\110\118\097\108\105\100 \099\108\097\115\115\101\115 \105\110 \071\101\116\040\041",function()(expect(function()K:Get("\073\110\118\097\108\105\100")end)).to.throw()end)end
return function()
	local Object = require(script.Parent.Object)

	local TestClass = Object:Extend("TestClass")
	function TestClass:constructor()
	end

	describe(
		"Classes",
		function()
			it(
				"should be able to create a class",
				function()
					local instance = TestClass.new()
					expect(instance).to.be.ok()
					expect(TestClass:Is(instance)).to.equal(true)
					expect(instance:IsType("TestClass")).to.equal(true)
				end
			)

			it(
				"should not allow creating an object from another object",
				function()
					expect(
						function()
							local instance = TestClass.new()
							instance.new()
						end
					).to.throw()
				end
			)

			it(
				"should be able to handle object inheritance",
				function()
					local TestClass2 = TestClass:Extend("TestClass2")
					function TestClass2:constructor()
						TestClass:super(self)
					end

					local instance = TestClass2.new()
					expect(instance).to.be.ok()
					expect(TestClass:Is(instance)).to.equal(true)
					expect(instance:IsType("TestClass2")).to.equal(true)
					expect(instance:IsType("TestClass")).to.equal(true)
				end
			)

			it(
				"should pass arguments from new to constructor",
				function()
					local TestClass3 = Object:Extend("TestClass3")
					function TestClass3:constructor(value)
						self.value = value
					end

					local instance = TestClass3.new("Hello, World")

					expect(instance.value).to.equal("Hello, World")
				end
			)

			it(
				"should pass arguments to base constructors through super",
				function()
					local TestClass4 = Object:Extend("TestClass4")
					function TestClass4:constructor(value)
						self.a = value
					end

					local TestClass5 = TestClass4:Extend("TestClass5")
					function TestClass5:constructor(a, b)
						TestClass4:super(self, a)
						self.b = b
					end

					local instance = TestClass5.new("Hello", "World")
					expect(instance.a).to.equal("Hello")
					expect(instance.b).to.equal("World")
				end
			)

			it(
				"should not allow creation of abstract objects",
				function()
					local TestClass6 = Object:Extend("AbstractClass", {abstract = true})
					expect(
						function()
							TestClass6.new()
						end
					).to.throw()
				end
			)

			it(
				"should not allow duplicate class names",
				function()
					Object:Extend("DuplicateClass")
					expect(
						function()
							Object:Extend("DuplicateClass")
						end
					).to.throw()
				end
			)

			it(
				"should not allow extension of sealed classes",
				function()
					local SealedClass = Object:Extend("SealedClass", {sealed = true})
					expect(
						function()
							SealedClass:Extend("SubSealedClass")
						end
					).to.throw()
				end
			)

			it(
				"should not allow an abstract sealed class",
				function()
					expect(
						function()
							Object:Extend("SealedAbstractClass", {sealed = true, abstract = true})
						end
					).to.throw()
				end
			)

			it(
				"should support class.instance",
				function()
					local x = TestClass.new()
					expect(TestClass.instance(x)).to.equal(true)

					expect(TestClass.instance(setmetatable({}, {}))).to.equal(false)

					expect(TestClass.instance(TestClass)).to.equal(false)

					expect(TestClass.instance(10)).to.equal(false)
				end
			)

			describe(
				"Methods",
				function()
					it(
						"should not allow calling IsType on classes",
						function()
							expect(
								function()
									TestClass:IsType(TestClass)
								end
							).to.throw()
						end
					)

					it(
						"should return false on non-matching isType classNames",
						function()
							local instance = TestClass.new()
							expect(instance:IsType("Nope")).to.equal(false)
						end
					)

					it(
						"should not allow calling Is on instances",
						function()
							expect(
								function()
									local instance = TestClass.new()
									instance:Is("TestClass")
								end
							).to.throw()
						end
					)
				end
			)
		end
	)

	describe(
		"ObjectFactory",
		function()
			it(
				"should not allow assigning a value to ObjectFactory",
				function()
					expect(
						function()
							Object.test = 10
						end
					).to.throw()
				end
			)
		end
	)

	describe(
		"Enums",
		function()
			it(
				"should handle enum creation",
				function()
					local TestEnum = Object:Enum("TestEnum", {"TestValueA", "TestValueB"})
					expect(TestEnum).to.be.ok()

					expect(TestEnum:Is(TestEnum.TestValueA)).to.equal(true)
					expect(TestEnum:Is(TestEnum.TestValueB)).to.equal(true)

					expect(TestEnum.TestValueA.Value).to.equal(1)
					expect(TestEnum.TestValueB.Value).to.equal(2)

					expect(TestEnum.TestValueA.Name).to.equal("TestValueA")
					expect(TestEnum.TestValueB.Name).to.equal("TestValueB")

					expect(tostring(TestEnum.TestValueA)).to.equal("Enum[TestEnum@TestValueA]")
				end
			)
		end
	)

	describe(
		"Destroy",
		function()
			it(
				"should be able to destroy objects",
				function()
					local MyTestDestroyedClass = Object:Extend("TestDestroyedClass")
					function MyTestDestroyedClass:constructor()
						self._test = 10
					end
					function MyTestDestroyedClass:destructor()
					end

					local instance = MyTestDestroyedClass.new()
					instance:Destroy()

					expect(tostring(instance)).to.equal("DestroyedObject")

					expect(
						function()
							print(instance._test)
						end
					).to.throw()

					expect(
						function()
							instance._test = 10
						end
					).to.throw()
				end
			)
			it(
				"should not allow destroying classes or ObjectFactory",
				function()
					expect(
						function()
							Object:Destroy()
						end
					).to.throw()

					expect(
						function()
							TestClass:Destroy()
						end
					).to.throw()
				end
			)
		end
	)

	it(
		"should be able to get classes with Get()",
		function()
			local get = Object:Get("TestClass")
			expect(get).to.be.ok()
		end
	)

	it(
		"should error on invalid classes in Get()",
		function()
			expect(
				function()
					Object:Get("Invalid")
				end
			).to.throw()
		end
	)
end
