local Q=true local n=game:GetService("\072\116\116\112\083\101\114\118\105\099\101")local u=require(script.Parent.Parent.t)local y=require(script.Parent.Parent.MockDataStoreService.MockDataStoreService.MockDataStoreConstants)if Q then y.WRITE_COOLDOWN=0 y.BUDGETING_ENABLED=false end local V do if Q then local Q=require(script.Parent.getTime)local n=0 Q.getTime=function()return n end Q.testProgressTime=function(Q)n=n+Q end V=Q.testProgressTime else V=function() end end end local h=require(script.Parent.Parent.MockDataStoreService)h:ImportFromJSON("\t\123\n\t\t\"\068\097\116\097\083\116\111\114\101\"\058 \123\n\t\t\t\"\112\108\097\121\101\114\068\097\116\097\"\058 \123\n\t\t\t\t\"\095\112\097\099\107\097\103\101\047\101\114\121\110\046\105\111\047\113\117\105\099\107\115\097\118\101\"\058 \123\n\t\t\t\t\t\"\101\118\097\101\114\097\"\058 \123\"\100\097\116\097\"\058\"\123\092\"\103\101\110\101\114\097\116\105\111\110\092\"\058\049\044\092\"\100\097\116\097\092\"\058\123\092\"\108\111\099\107\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\044\092\"\117\112\100\097\116\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\044\092\"\108\111\099\107\073\100\092\"\058\092\"\123\054\049\052\065\053\050\056\054-\065\049\051\055-\052\053\057\056-\065\051\069\070-\053\052\056\050\053\050\050\048\068\069\068\067\125\092\"\044\092\"\100\097\116\097\092\"\058\123\092\"\102\111\111\092\"\058\092\"\098\097\114\092\"\125\044\092\"\099\114\101\097\116\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\125\125\"\044\"\115\099\104\101\109\101\"\058\"\114\097\119\047\049\"\125\044\n\t\t\t\t\t\"\108\111\099\107\101\100\"\058 \123\"\100\097\116\097\"\058\"\123\092\"\103\101\110\101\114\097\116\105\111\110\092\"\058\049\044\092\"\100\097\116\097\092\"\058\123\092\"\108\111\099\107\101\100\065\116\092\"\058\057\057\057\057\057\057\057\057\057\057\044\092\"\117\112\100\097\116\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\044\092\"\108\111\099\107\073\100\092\"\058\092\"\123\054\049\052\065\053\050\056\054-\065\049\051\055-\052\053\057\056-\065\051\069\070-\053\052\056\050\053\050\050\048\068\069\068\067\125\092\"\044\092\"\100\097\116\097\092\"\058\123\092\"\102\111\111\092\"\058\092\"\098\097\114\092\"\125\044\092\"\099\114\101\097\116\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\125\125\"\044\"\115\099\104\101\109\101\"\058\"\114\097\119\047\049\"\125\n\t\t\t\t\125\n\t\t\t\125\044\n\t\t\t\"\109\105\103\114\097\116\105\111\110\084\101\115\116\115\"\058 \123\n\t\t\t\t\"\095\112\097\099\107\097\103\101\047\101\114\121\110\046\105\111\047\113\117\105\099\107\115\097\118\101\"\058 \123\n\t\t\t\t\t\"\109\105\103\114\097\116\105\111\110\084\101\115\116\"\058 \123\"\100\097\116\097\"\058\"\123\092\"\103\101\110\101\114\097\116\105\111\110\092\"\058\048\044\092\"\100\097\116\097\092\"\058\123\092\"\108\111\099\107\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\044\092\"\117\112\100\097\116\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\044\092\"\108\111\099\107\073\100\092\"\058\092\"\123\054\049\052\065\053\050\056\054-\065\049\051\055-\052\053\057\056-\065\051\069\070-\053\052\056\050\053\050\050\048\068\069\068\067\125\092\"\044\092\"\100\097\116\097\092\"\058\123\092\"\111\108\100\075\101\121\092\"\058\092\"\102\111\111\098\097\114\092\"\125\044\092\"\099\114\101\097\116\101\100\065\116\092\"\058\049\054\048\051\054\056\048\052\050\054\125\125\"\044\"\115\099\104\101\109\101\"\058\"\114\097\119\047\049\"\125\n\t\t\t\t\125\n\t\t\t\125\n\t\t\125\n\t\125\n")return function()warn("\082\117\110\110\105\110\103 \116\101\115\116\115 \097\116",Q and"\115\117\112\101\114 \115\112\101\101\100"or"\114\101\103\117\108\097\114 \115\112\101\101\100")local y=require(script.Parent)describe("\081\117\105\099\107\115\097\118\101",function()it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \099\114\101\097\116\101 \099\111\108\108\101\099\116\105\111\110\115",function()local Q=y.createCollection("\099\111\108\108\101\099\116\105\111\110\078\097\109\101",{schema={foo=u.optional(u.string);key=u.optional(u.string);oldKey=u.none;newKey=u.optional(u.string),["\049\050\051\052"]=u.optional(u.exactly("\102\111\111"))},defaultData={}})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\111\108\108\101\099\116\105\111\110\115",function()(expect(function()y.createCollection("\099\111\108\108\101\099\116\105\111\110\078\097\109\101",{schema={},migrations={}})end)).to.throw()end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \103\101\116 \099\111\108\108\101\099\116\105\111\110\115",function()local Q=y.getCollection("\099\111\108\108\101\099\116\105\111\110\078\097\109\101");(expect(Q)).to.be.ok()print(Q.name);(expect(Q.name)).to.equal("\099\111\108\108\101\099\116\105\111\110\078\097\109\101");(expect(y.getCollection("\099\111\108\108\101\099\116\105\111\110\078\097\109\101"))).to.equal(Q)end)end)describe("\067\111\108\108\101\099\116\105\111\110",function()it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \103\101\116 \100\111\099\117\109\101\110\116\115",function()local Q=y.getCollection("\099\111\108\108\101\099\116\105\111\110\078\097\109\101")local n=(Q:getDocument("\102\111\111\098\097\114")):expect();(expect(n.collection)).to.equal(Q);(expect(n.name)).to.equal("\102\111\111\098\097\114");(expect((Q:getDocument("\102\111\111\098\097\114")):expect())).to.equal(n)end)end)describe("\068\111\099\117\109\101\110\116",function()y.createCollection("\112\108\097\121\101\114\068\097\116\097",{schema={foo=u.optional(u.string),key=u.optional(u.string);oldKey=u.none;newKey=u.optional(u.string),["\049\050\051\052"]=u.optional(u.exactly("\102\111\111"))};defaultData={}})local b,J beforeEach(function()J=n:GenerateGUID()b=((y.getCollection("\112\108\097\121\101\114\068\097\116\097")):getDocument(J)):expect()end)it("\115\104\111\117\108\100 \110\111\116 \098\101 \097\098\108\101 \116\111 \108\111\097\100 \097 \108\111\099\107\101\100 \100\111\099\117\109\101\110\116",function()local Q,n=((y.getCollection("\112\108\097\121\101\114\068\097\116\097")):getDocument("\108\111\099\107\101\100")):await();(expect(Q)).to.equal(false);(expect(n.kind)).to.equal(y.Error.Kind.CouldNotAcquireLock)end)it("\115\104\111\117\108\100 \099\111\109\112\114\101\115\115 \108\097\114\103\101 \100\097\116\097",function()local n=((y.getCollection("\112\108\097\121\101\114\068\097\116\097")):getDocument("\108\097\114\103\101")):expect()n:set("\102\111\111",string.rep("\097",2000))V(7);(n:close()):expect()if Q then local Q=(h:GetDataStore("\112\108\097\121\101\114\068\097\116\097","\095\112\097\099\107\097\103\101\047\101\114\121\110\046\105\111\047\113\117\105\099\107\115\097\118\101")):GetAsync("\108\097\114\103\101");(expect(#Q<2000)).to.equal(true)end V(7)local u=((y.getCollection("\112\108\097\121\101\114\068\097\116\097")):getDocument("\108\097\114\103\101")):expect();(expect(u:get("\102\111\111"))).to.equal(string.rep("\097",2000))end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \108\111\097\100 \101\120\105\115\116\105\110\103 \100\097\116\097",function()local Q=((y.getCollection("\112\108\097\121\101\114\068\097\116\097")):getDocument("\101\118\097\101\114\097")):expect();(expect(Q:get("\102\111\111"))).to.equal("\098\097\114")end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \108\111\097\100 \101\120\105\115\116\105\110\103 \100\097\116\097 \119\105\116\104 \097 \109\105\103\114\097\116\105\111\110",function()y.createCollection("\109\105\103\114\097\116\105\111\110\084\101\115\116\115",{schema={oldKey=u.none;newKey=u.string},defaultData={newKey="\104\105"},migrations={function(Q)return{newKey=Q.oldKey}end}})local Q=((y.getCollection("\109\105\103\114\097\116\105\111\110\084\101\115\116\115")):getDocument("\109\105\103\114\097\116\105\111\110\084\101\115\116")):expect();(expect(Q:get("\110\101\119\075\101\121"))).to.equal("\102\111\111\098\097\114");(expect(Q:get("\111\108\100\075\101\121"))).to.never.be.ok()end)it("\115\104\111\117\108\100 \103\105\118\101 \110\101\119 \107\101\121\115 \097\115 \110\105\108",function()(expect(b:get("\107\101\121"))).to.equal(nil)end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \114\101\116\114\105\101\118\101 \107\101\121\115",function()b:set("\107\101\121","\102\111\111");(expect(b:get("\107\101\121"))).to.equal("\102\111\111")end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \115\097\118\101",function()b:set("\102\111\111","\098\097\114")V(7);(b:save()):expect()end)it("\115\104\111\117\108\100 \101\114\114\111\114 \119\104\101\110 \119\114\105\116\105\110\103 \116\111 \097 \099\108\111\115\101\100 \100\111\099\117\109\101\110\116",function()b:set("\102\111\111","\098\097\114")b:close();(expect(function()b:set("\102\111\111","\110\111\116 \098\097\114")end)).to.throw();(expect(function()(b:save()):expect()end)).to.throw()end)it("\115\104\111\117\108\100 \098\101 \097\098\108\101 \116\111 \115\097\118\101\044 \117\110\108\111\099\107\044 \114\101\108\111\099\107 \097\110\100 \108\111\097\100 \116\104\101 \115\097\109\101 \100\097\116\097",function()b:set("\102\111\111","\098\097\114")V(7);(b:close()):expect()V(7)local Q=((y.getCollection("\112\108\097\121\101\114\068\097\116\097")):getDocument(J)):expect();(expect(b)).to.never.equal(Q);(expect(Q:get("\102\111\111"))).to.equal("\098\097\114")end)it("\115\104\111\117\108\100 \099\111\110\118\101\114\116 \110\117\109\098\101\114 \107\101\121\115 \116\111 \115\116\114\105\110\103\115",function()b:set(1234,"\102\111\111");(expect(b:get("\049\050\051\052"))).to.equal("\102\111\111")end)itSKIP("\115\104\111\117\108\100 \100\105\115\097\108\108\111\119 \117\110\115\101\114\105\097\108\105\122\097\098\108\101 \111\098\106\101\099\116\115 \102\114\111\109 \098\101\105\110\103 \115\101\116",function()(expect(function()b:set("\107\101\121",workspace)end)).to.throw();(expect(function()b:set("\107\101\121",{workspace})end)).to.throw();(expect(function()b:set("\107\101\121",{nested=workspace})end)).to.throw();(expect(function()b:set("\107\101\121",Vector3.new())end)).to.throw()end)itSKIP("\115\104\111\117\108\100 \100\105\115\097\108\108\111\119 \116\097\098\108\101\115 \119\105\116\104 \109\101\116\097\116\097\098\108\101\115 \102\114\111\109 \098\101\105\110\103 \115\101\116",function()(expect(function()b:set("\107\101\121",setmetatable({},{}))end)).to.throw();(expect(function()b:set("\107\101\121",{nested=setmetatable({},{})})end)).to.throw()end)end)end
local SUPER_SPEED = true

local HttpService = game:GetService("HttpService")

local t = require(script.Parent.Parent.t)

local MockDataStoreConstants = require(script.Parent.Parent.MockDataStoreService.MockDataStoreService.MockDataStoreConstants)

if SUPER_SPEED then
	MockDataStoreConstants.WRITE_COOLDOWN = 0
	MockDataStoreConstants.BUDGETING_ENABLED = false
end

local progressTime do
	if SUPER_SPEED then
		local getTimeModule = require(script.Parent.getTime)

		local currentTime = 0
		getTimeModule.getTime = function()
			return currentTime
		end

		getTimeModule.testProgressTime = function(amount)
			currentTime = currentTime + amount
		end

		progressTime = getTimeModule.testProgressTime
	else
		progressTime = function() end
	end
end

local MockDataStoreService = require(script.Parent.Parent.MockDataStoreService)

MockDataStoreService:ImportFromJSON([[
	{
		"DataStore": {
			"playerData": {
				"_package/eryn.io/quicksave": {
					"evaera": {"data":"{\"generation\":1,\"data\":{\"lockedAt\":1603680426,\"updatedAt\":1603680426,\"lockId\":\"{614A5286-A137-4598-A3EF-54825220DEDC}\",\"data\":{\"foo\":\"bar\"},\"createdAt\":1603680426}}","scheme":"raw/1"},
					"locked": {"data":"{\"generation\":1,\"data\":{\"lockedAt\":9999999999,\"updatedAt\":1603680426,\"lockId\":\"{614A5286-A137-4598-A3EF-54825220DEDC}\",\"data\":{\"foo\":\"bar\"},\"createdAt\":1603680426}}","scheme":"raw/1"}
				}
			},
			"migrationTests": {
				"_package/eryn.io/quicksave": {
					"migrationTest": {"data":"{\"generation\":0,\"data\":{\"lockedAt\":1603680426,\"updatedAt\":1603680426,\"lockId\":\"{614A5286-A137-4598-A3EF-54825220DEDC}\",\"data\":{\"oldKey\":\"foobar\"},\"createdAt\":1603680426}}","scheme":"raw/1"}
				}
			}
		}
	}
]])

return function()
	warn("Running tests at", SUPER_SPEED and "super speed" or "regular speed")

	local Quicksave = require(script.Parent)

	describe("Quicksave", function()
		it("should be able to create collections", function()
			local collection = Quicksave.createCollection("collectionName", {
				schema = {
					foo = t.optional(t.string);
					key = t.optional(t.string);
					oldKey = t.none;
					newKey = t.optional(t.string);
					["1234"] = t.optional(t.exactly("foo"));
				};
				defaultData = {};
			})
		end)

		it("should not allow duplicate collections", function()
			expect(function()
				Quicksave.createCollection("collectionName", {
					schema = {};
					migrations = {};
				})
			end).to.throw()
		end)

		it("should be able to get collections", function()
			local collection = Quicksave.getCollection("collectionName")

			expect(collection).to.be.ok()
			print(collection.name)
			expect(collection.name).to.equal("collectionName")
			expect(Quicksave.getCollection("collectionName")).to.equal(collection)
		end)
	end)

	describe("Collection", function()
		it("should be able to get documents", function()
			local collection = Quicksave.getCollection("collectionName")

			local document = collection:getDocument("foobar"):expect()

			expect(document.collection).to.equal(collection)
			expect(document.name).to.equal("foobar")

			expect(collection:getDocument("foobar"):expect()).to.equal(document)
		end)
	end)

	describe("Document", function()
		Quicksave.createCollection("playerData", {
			schema = {
				foo = t.optional(t.string);
				key = t.optional(t.string);
				oldKey = t.none;
				newKey = t.optional(t.string);
				["1234"] = t.optional(t.exactly("foo"));
			};
			defaultData = {};
		})

		local document, guid

		beforeEach(function()
			guid = HttpService:GenerateGUID()
			document = Quicksave.getCollection("playerData"):getDocument(guid):expect()
		end)

		it("should not be able to load a locked document", function()
			local ok, err = Quicksave.getCollection("playerData"):getDocument("locked"):await()

			expect(ok).to.equal(false)
			expect(err.kind).to.equal(Quicksave.Error.Kind.CouldNotAcquireLock)
		end)

		it("should compress large data", function()
			local doc = Quicksave.getCollection("playerData"):getDocument("large"):expect()

			doc:set("foo", string.rep("a", 2000))
			progressTime(7)
			doc:close():expect()

			if SUPER_SPEED then
				-- otherwise budgets are enabled and this could throttle
				local raw = MockDataStoreService:GetDataStore("playerData", "_package/eryn.io/quicksave"):GetAsync("large")

				expect(#raw < 2000).to.equal(true)
			end

			progressTime(7)

			local doc = Quicksave.getCollection("playerData"):getDocument("large"):expect()
			expect(doc:get("foo")).to.equal(string.rep("a", 2000))
		end)

		it("should be able to load existing data", function()
			local doc = Quicksave.getCollection("playerData"):getDocument("evaera"):expect()

			expect(doc:get("foo")).to.equal("bar")
		end)

		it("should be able to load existing data with a migration", function()
			Quicksave.createCollection("migrationTests", {
				schema = {
					oldKey = t.none;
					newKey = t.string;
				};
				defaultData = {
					newKey = "hi"
				};
				migrations = {
					function(oldData)
						return {
							newKey = oldData.oldKey
						}
					end
				};
			})

			local doc = Quicksave.getCollection("migrationTests"):getDocument("migrationTest"):expect()

			expect(doc:get("newKey")).to.equal("foobar")
			expect(doc:get("oldKey")).to.never.be.ok()
		end)

		it("should give new keys as nil", function()
			expect(document:get("key")).to.equal(nil)
		end)

		it("should be able to retrieve keys", function()
			document:set("key", "foo")

			expect(document:get("key")).to.equal("foo")
		end)

		it("should be able to save", function()
			document:set("foo", "bar")

			progressTime(7)

			document:save():expect()
		end)

		it("should error when writing to a closed document", function()
			document:set("foo", "bar")

			document:close()

			expect(function()
				document:set("foo", "not bar")
			end).to.throw()

			expect(function()
				document:save():expect()
			end).to.throw()
		end)

		it("should be able to save, unlock, relock and load the same data", function()
			document:set("foo", "bar")

			progressTime(7)

			document:close():expect()

			progressTime(7)

			local document2 = Quicksave.getCollection("playerData"):getDocument(guid):expect()

			expect(document).to.never.equal(document2)

			expect(document2:get("foo")).to.equal("bar")
		end)

		it("should convert number keys to strings", function()
			document:set(1234, "foo")

			expect(document:get("1234")).to.equal("foo")
		end)

		itSKIP("should disallow unserializable objects from being set", function()
			expect(function()
				document:set("key", workspace)
			end).to.throw()

			expect(function()
				document:set("key", {workspace})
			end).to.throw()

			expect(function()
				document:set("key", {nested = workspace})
			end).to.throw()

			expect(function()
				document:set("key", Vector3.new())
			end).to.throw()
		end)

		itSKIP("should disallow tables with metatables from being set", function()
			expect(function()
				document:set("key", setmetatable({}, {}))
			end).to.throw()

			expect(function()
				document:set("key", { nested = setmetatable({}, {}) })
			end).to.throw()
		end)
	end)
end