-- SPDX-FileCopyrightText: © 2026 Vladimir Zorin -- SPDX-License-Identifier: OWL-1.0 or later local testimony = require("testimony") local std = require("std") local mneme = require("mneme") local testify = testimony.new("== mneme: lists ==") local tmp_path = function() return "/tmp/mneme_list_" .. std.nanoid() .. ".mneme" end testify:that("rpush and range returns all items in order", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") lst:rpush("first") lst:rpush("second") lst:rpush("third") local items = lst:range(0, -1) testimony.assert_equal(3, #items) testimony.assert_equal("first", items[1]) testimony.assert_equal("second", items[2]) testimony.assert_equal("third", items[3]) db:close() std.fs.remove(path) end) testify:that("lpush prepends items", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") lst:rpush("middle") lst:lpush("first") lst:rpush("last") local items = lst:range(0, -1) testimony.assert_equal(3, #items) testimony.assert_equal("first", items[1]) testimony.assert_equal("middle", items[2]) testimony.assert_equal("last", items[3]) db:close() std.fs.remove(path) end) testify:that("rpop returns and removes last item", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") lst:rpush("a") lst:rpush("b") lst:rpush("c") local val = lst:rpop() testimony.assert_equal("c", val) testimony.assert_equal(2, lst:len()) val = lst:rpop() testimony.assert_equal("b", val) db:close() std.fs.remove(path) end) testify:that("lpop returns and removes first item", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") lst:rpush("a") lst:rpush("b") lst:rpush("c") local val = lst:lpop() testimony.assert_equal("a", val) testimony.assert_equal(2, lst:len()) db:close() std.fs.remove(path) end) testify:that("empty pop returns nil", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") testimony.assert_nil(lst:rpop()) testimony.assert_nil(lst:lpop()) db:close() std.fs.remove(path) end) testify:that("len tracks correctly through push/pop", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") testimony.assert_equal(0, lst:len()) local n = lst:rpush("a") testimony.assert_equal(1, n) testimony.assert_equal(1, lst:len()) lst:rpush("b") lst:rpush("c") testimony.assert_equal(3, lst:len()) lst:lpop() testimony.assert_equal(2, lst:len()) lst:rpop() lst:rpop() testimony.assert_equal(0, lst:len()) db:close() std.fs.remove(path) end) testify:that("index returns correct element (0-based)", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") lst:rpush("zero") lst:rpush("one") lst:rpush("two") lst:rpush("three") testimony.assert_equal("zero", lst:index(0)) testimony.assert_equal("two", lst:index(2)) testimony.assert_equal("three", lst:index(3)) -- Negative index testimony.assert_equal("three", lst:index(-1)) testimony.assert_equal("two", lst:index(-2)) -- Out of bounds testimony.assert_nil(lst:index(4)) testimony.assert_nil(lst:index(-5)) db:close() std.fs.remove(path) end) testify:that("range with subset indices", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") for i = 0, 9 do lst:rpush("item" .. i) end local first3 = lst:range(0, 2) testimony.assert_equal(3, #first3) testimony.assert_equal("item0", first3[1]) testimony.assert_equal("item2", first3[3]) local last2 = lst:range(-2, -1) testimony.assert_equal(2, #last2) testimony.assert_equal("item8", last2[1]) testimony.assert_equal("item9", last2[2]) db:close() std.fs.remove(path) end) testify:that("interleaved lpush/rpush/lpop/rpop maintains consistency", function() local path = tmp_path() local db = mneme.open(path, { sync = "none" }) local lst = db:keyspace("t"):list("q") lst:rpush("a") -- [a] lst:rpush("b") -- [a, b] lst:lpush("z") -- [z, a, b] lst:rpush("c") -- [z, a, b, c] lst:lpop() -- [a, b, c] lst:rpop() -- [a, b] lst:lpush("x") -- [x, a, b] local items = lst:range(0, -1) testimony.assert_equal(3, #items) testimony.assert_equal("x", items[1]) testimony.assert_equal("a", items[2]) testimony.assert_equal("b", items[3]) db:close() std.fs.remove(path) end) testify:conclude()