File

spec/util_dbuffer_spec.lua @ 12995:e385f3a06673

moduleapi: Add 'peek' to :may() and new :could() helper to suppress logging The current method logs scary "access denied" messages on failure - this is generally very useful when debugging access control stuff, but in some cases the call is simply a check to see if someone *could* perform an action, even if they haven't requested it yet. One example is determining whether to show the user as an admin in disco. The 'peek' parameter, if true, will suppress such logging. The :could() method is just a simple helper that can make the calling code a bit more readable (suggested by Zash).
author Matthew Wild <mwild1@gmail.com>
date Sun, 26 Mar 2023 14:06:04 +0100
parent 12764:bf6d2f9fad4d
line wrap: on
line source

local dbuffer = require "util.dbuffer";
describe("util.dbuffer", function ()
	describe("#new", function ()
		it("has a constructor", function ()
			assert.Function(dbuffer.new);
		end);
		it("can be created", function ()
			assert.truthy(dbuffer.new());
			assert.truthy(dbuffer.new(1));
			assert.truthy(dbuffer.new(1024));
		end);
		it("won't create an empty buffer", function ()
			assert.falsy(dbuffer.new(0));
		end);
		it("won't create a negatively sized buffer", function ()
			assert.falsy(dbuffer.new(-1));
		end);
	end);
	describe(":write", function ()
		local b = dbuffer.new(10, 3);
		it("works", function ()
			assert.truthy(b:write("hi"));
		end);
		it("fails when the buffer is full", function ()
			local ret = b:write(" there world, this is a long piece of data");
			assert.is_falsy(ret);
		end);
		it("works when max_chunks is reached", function ()
			-- Chunks are an optimization, dbuffer should collapse chunks when needed
			for _ = 1, 8 do
				assert.truthy(b:write("!"));
			end
			assert.falsy(b:write("!")); -- Length reached
		end);
	end);

	describe(":read", function ()
		it("supports optional bytes parameter", function ()
			-- should return the frontmost chunk
			local b = dbuffer.new();
			assert.truthy(b:write("hello"));
			assert.truthy(b:write(" "));
			assert.truthy(b:write("world"));
			assert.equal("h", b:read(1));

			assert.equal("ello", b:read());
			assert.equal(" ", b:read());
			assert.equal("world", b:read());
		end);
		it("fails when there is not enough data in the buffer", function ()
			local b = dbuffer.new(12);
			b:write("hello");
			b:write(" ");
			b:write("world");
			assert.is_falsy(b:read(12));
			assert.is_falsy(b:read(13));
		end);
	end);

	describe(":read_until", function ()
		it("works", function ()
			local b = dbuffer.new();
			b:write("hello\n");
			b:write("world");
			b:write("\n");
			b:write("\n\n");
			b:write("stuff");
			b:write("more\nand more");

			assert.equal(nil, b:read_until("."));
			assert.equal(nil, b:read_until("%"));
			assert.equal("hello\n", b:read_until("\n"));
			assert.equal("world\n", b:read_until("\n"));
			assert.equal("\n", b:read_until("\n"));
			assert.equal("\n", b:read_until("\n"));
			assert.equal("stu", b:read(3));
			assert.equal("ffmore\n", b:read_until("\n"));
			assert.equal(nil, b:read_until("\n"));
			assert.equal("and more", b:read_chunk());
		end);
	end);

	describe(":discard", function ()
		local b = dbuffer.new();
		it("works", function ()
			assert.truthy(b:write("hello world"));
			assert.truthy(b:discard(6));
			assert.equal(5, b:length());
			assert.equal(5, b:len());
			assert.equal("world", b:read(5));
		end);
		it("works across chunks", function ()
			assert.truthy(b:write("hello"));
			assert.truthy(b:write(" "));
			assert.truthy(b:write("world"));
			assert.truthy(b:discard(3));
			assert.equal(8, b:length());
			assert.truthy(b:discard(3));
			assert.equal(5, b:length());
			assert.equal("world", b:read(5));
		end);
		it("can discard the entire buffer", function ()
			assert.equal(b:len(), 0);
			assert.truthy(b:write("hello world"));
			assert.truthy(b:discard(11));
			assert.equal(0, b:len());
			assert.truthy(b:write("hello world"));
			assert.truthy(b:discard(12));
			assert.equal(0, b:len());
			assert.truthy(b:write("hello world"));
			assert.truthy(b:discard(128));
			assert.equal(0, b:len());
		end);
		it("works on an empty buffer", function ()
			assert.truthy(dbuffer.new():discard());
			assert.truthy(dbuffer.new():discard(0));
			assert.truthy(dbuffer.new():discard(1));
		end);
	end);

	describe(":collapse()", function ()
		it("works", function ()
			local b = dbuffer.new();
			b:write("hello");
			b:write(" ");
			b:write("world");
			b:collapse(6);
			local ret, bytes = b:read_chunk();
			assert.equal("hello ", ret);
			assert.equal(6, bytes);
		end);
		it("works on an empty buffer", function ()
			local b = dbuffer.new();
			b:collapse();
		end);
	end);

	describe(":sub", function ()
		-- Helper function to compare buffer:sub() with string:sub()
		local s = "hello world";
		local function test_sub(b, x, y)
			local string_result, buffer_result = s:sub(x, y), b:sub(x, y);
			assert.equals(string_result, buffer_result, ("buffer:sub(%d, %s) does not match string:sub()"):format(x, y and ("%d"):format(y) or "nil"));
		end

		it("works", function ()
			local b = dbuffer.new();
			assert.truthy(b:write("hello world"));
			assert.equals("hello", b:sub(1, 5));
		end);

		it("works after discard", function ()
			local b = dbuffer.new(256);
			assert.truthy(b:write("foobar"));
			assert.equals("foobar", b:sub(1, 6));
			assert.truthy(b:discard(3)); -- consume "foo"
			assert.equals("bar", b:sub(1, 3));
		end);

		it("supports optional end parameter", function ()
			local b = dbuffer.new();
			assert.truthy(b:write("hello world"));
			assert.equals("hello world", b:sub(1));
			assert.equals("world", b:sub(-5));
		end);

		it("is equivalent to string:sub", function ()
			local b = dbuffer.new(11);
			assert.truthy(b:write(s));
			for i = -13, 13 do
				for j = -13, 13 do
					test_sub(b, i, j);
				end
			end
		end);

		it("works on an empty buffer", function ()
			local b = dbuffer.new();
			assert.equal("", b:sub(1, 12));
		end);
	end);

	describe(":byte", function ()
		-- Helper function to compare buffer:byte() with string:byte()
		local s = "hello world"
		local function test_byte(b, x, y)
			local string_result, buffer_result = {s:byte(x, y)}, {b:byte(x, y)};
			assert.same(
				string_result,
				buffer_result,
				("buffer:byte(%s, %s) does not match string:byte()"):format(x and ("%d"):format(x) or "nil", y and ("%d"):format(y) or "nil")
			);
		end

		it("is equivalent to string:byte", function ()
			local b = dbuffer.new(11);
			assert.truthy(b:write(s));
			test_byte(b, 1);
			test_byte(b, 3);
			test_byte(b, -1);
			test_byte(b, -3);
			test_byte(b, nil, 5);
			for i = -13, 13 do
				for j = -13, 13 do
					test_byte(b, i, j);
				end
			end
		end);

		it("works with characters > 127", function ()
			local b = dbuffer.new();
			b:write(string.char(0, 140));
			local r = { b:byte(1, 2) };
			assert.same({ 0, 140 }, r);
		end);

		it("works on an empty buffer", function ()
			local b = dbuffer.new();
			assert.equal("", b:sub(1,1));
		end);
	end);
end);