minetest-mm/mods/spectator_mode/spec/init_spec.lua
2024-12-19 12:55:40 +01:00

305 lines
12 KiB
Lua

-- main unit testing file that mineunit picks up
-- https://github.com/S-S-X/mineunit
require("mineunit")
mineunit("core")
mineunit("player")
mineunit("server")
mineunit('common/after')
-- mimic player_api.player_attached
fixture('player_api')
-- add some not yet included functions
fixture('mineunit_extensions')
-- mimic beerchat.has_player_muted_player
fixture('beerchat')
local function pd1(m) print(dump(m)) end
local function pd(...) for _, m in ipairs({...}) do pd1(m) end end
-- override chat_send_player to inspect what was sent
local chatlog = {}
local core_chat_send_player = core.chat_send_player
function core.chat_send_player(to_name, message)
table.insert(chatlog, { to = to_name, message = message })
return core_chat_send_player(to_name, message)
end
local function reset_chatlog() chatlog = {} end
describe("Mod initialization", function()
it("Wont crash", function()
sourcefile("init")
end)
end)
describe('Watching:', function()
-- create some players
local players = {
SX = Player("SX", { interact = 1 }),
boss = Player("boss", { interact = 1, watch = 1 }),
dude1 = Player("dude1", { interact = 1, }),
dude2 = Player("dude2", { interact = 1, }),
dude3 = Player("dude3", { interact = false, }),
}
local start_positions = {}
local boss = players.boss
local dude1 = players.dude1
local dude2 = players.dude2
local dude3 = players.dude3
setup(function()
-- make sure the privs are registered
mineunit:mods_loaded()
-- log on all players and move them to unique positions
local i, pos = 1
for name, player in pairs(players) do
mineunit:execute_on_joinplayer(player)
pos = vector.new(10 * i, 20 * i, 30 * i)
start_positions[name] = pos
player:set_pos(pos)
i = i + 1
end
end)
teardown(function()
mineunit:info('shutting down server')
for _, player in pairs(players) do
mineunit:execute_on_leaveplayer(player)
end
mineunit:execute_globalstep(100)
end)
it("boss attaches to dude1", function()
reset_chatlog()
boss:send_chat_message("/watch dude1")
assert.equals(1, #chatlog, 'unexpected amount of messages, '
.. 'was dude1 notified by accident')
assert.equals('boss', chatlog[1].to)
assert.equals(1, chatlog[1].message:find('^Watching "dude1" at %('))
local pos = boss:get_pos()
assert.equals(start_positions.dude1.x, pos.x)
assert.equals(start_positions.dude1.y - 5, pos.y)
assert.equals(start_positions.dude1.z - 20, pos.z)
end)
it('boss returns to start position and nobody is notified about it', function()
-- let's make sure boss is still attached, jic we change previous test
assert.is_false(vector.equals(start_positions.boss, boss:get_pos()),
'boss is still at starting position: unit setup error')
reset_chatlog()
boss:send_chat_message('/unwatch')
mineunit:execute_globalstep(1)
assert.equals(0, #chatlog, 'there was an error message sent to ?')
assert.is_true(vector.equals(start_positions.boss, boss:get_pos()),
'boss did not move back to starting position')
end)
it('boss tries to unwatch when not watching', function()
reset_chatlog()
boss:send_chat_message('/unwatch')
mineunit:execute_globalstep(1)
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.is_not_nil(chatlog[1].message:find('not observing'),
'unexpected chat response')
end)
it('player receives message when issuing /unwatch while not attached', function()
reset_chatlog()
dude1:send_chat_message('/unwatch')
mineunit:execute_globalstep(1)
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.is_not_nil(chatlog[1].message:find('not observing'),
'unexpected chat response')
end)
it('invitations are sent and expire', function()
reset_chatlog()
-- we also test multiple invites with space separation
dude2:send_chat_message('/watchme dude1 SX')
assert.equals('dude1', chatlog[1].to, 'dude1 did not get invited')
assert.equals('SX', chatlog[2].to, 'SX did not get invited')
assert.equals('dude2', chatlog[3].to, 'dude2 did not get message')
local message = chatlog[3].message
assert.is_true(message:find('"dude1"') and message:find('"SX"') and true,
'response message does not contain invities')
assert.is_not_nil(message:find('60 seconds'),
'response message does not contain expire info')
reset_chatlog()
mineunit:execute_globalstep(60)
assert.equals(4, #chatlog, 'unexpected chatlog count')
reset_chatlog()
players.SX:send_chat_message('/smy')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('SX', chatlog[1].to, 'message was not sent to SX but ' .. chatlog[1].to)
message = chatlog[1].message
assert.is_not_nil(message:find('timed%-out%.$'),
'time out message does not end with "timed-out."')
local pos = players.SX:get_pos()
assert.is_true(vector.equals(start_positions.SX, pos),
'Invitation did not expire, SX was moved.')
end)
it('watching by normal player not possible', function()
local pos = dude2:get_pos()
reset_chatlog()
dude2:send_chat_message('/watch dude1')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('dude2', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('to run this command'),
'unexpected error message')
assert.is_true(vector.equals(pos, dude2:get_pos()))
end)
it('inviting is not possible when not having invite priv', function()
local last_priv = spectator_mode.priv_invite
-- set needed priv to avoid using dude3, this allows us to test
-- minetest.conf settings
spectator_mode.priv_invite = 'testPrivThatDoesNotExist'
reset_chatlog()
-- we also test comma list
dude2:send_chat_message('/watchme dude1,SX')
assert.equals(1, #chatlog, 'unexpected chatlog count')
local message = chatlog[1].message
assert.is_not_nil(message:find('"dude1"'), 'did not parse player list correctly')
assert.is_not_nil(message:find('"SX"'), 'did not parse player list correctly')
assert.is_not_nil(message:find('^You may not invite'), 'did not revoke inivting')
assert.is_nil(message:find('60 seconds'), 'time out message was wrongfully added')
-- restore priv setting
spectator_mode.priv_invite = last_priv
end)
it('player can not invite himself', function()
reset_chatlog()
dude1:send_chat_message('/watchme dude1')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('dude1', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('may not watch yourself'),
'unexpected chat response')
end)
it('moderator can not invite himself', function()
reset_chatlog()
boss:send_chat_message('/watchme boss')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('boss', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('may not watch yourself'),
'unexpected chat response')
end)
it('moderator can not attach to an observing player and gets name of observed player', function()
dude1:send_chat_message('/watchme dude2')
dude2:send_chat_message('/smy')
mineunit:execute_globalstep(1)
reset_chatlog()
boss:send_chat_message('/watch dude2')
mineunit:execute_globalstep(1)
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('boss', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^"dude2" is watching "dude1"'),
'unexpected chat response')
end)
it('player can not invite an observing player', function()
reset_chatlog()
players.SX:send_chat_message('/watchme dude2')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('SX', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^"dude2".*watching another player%.$'),
'unexpected chat response')
end)
-- TODO: check if this can't be exploited to make circular attaching
it('player can invite an observed player', function()
reset_chatlog()
players.SX:send_chat_message('/watchme dude1')
assert.equals(2, #chatlog, 'unexpected chatlog count')
assert.equals('dude1', chatlog[1].to, 'unexpected recipient.')
assert.equals('SX', chatlog[2].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^"SX".* seconds%.$'),
'unexpected chat response')
end)
it('player can deny an invite', function()
reset_chatlog()
dude1:send_chat_message('/smn')
assert.equals(2, #chatlog, 'unexpected chatlog count')
assert.equals('SX', chatlog[1].to, 'unexpected recipient.')
assert.equals('dude1', chatlog[2].to, 'unexpected recipient.')
end)
it('player can detach and returns to original position', function()
reset_chatlog()
dude2:send_chat_message('/unwatch')
mineunit:execute_globalstep(1)
assert.is_true(vector.equals(start_positions.dude2, dude2:get_pos()),
'dude2 did not move back to starting position')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('dude1', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^"dude2" has stopped loo'),
'unexpected chat response')
end)
it('can not invite a player with pending invitation', function()
dude1:send_chat_message('/watchme dude2')
reset_chatlog()
players.SX:send_chat_message('/watchme dude2')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('SX', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^"dude2" has a pen'),
'unexpected chat response')
end)
it('boss can attach to an unwatched player with pending invitation', function()
reset_chatlog()
boss:send_chat_message('/watch dude2')
mineunit:execute_globalstep(1)
assert.is_true(vector.equals(boss:get_pos(), vector.add(
dude2:get_pos(), vector.new(0, -5, -20))), 'boss not with dude2')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('boss', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^Watching "dude2"'),
'unexpected chat response')
end)
it('can accept invitation after a moderator also attached', function()
reset_chatlog()
dude2:send_chat_message('/smy')
mineunit:execute_globalstep(1)
assert.equals(2, #chatlog, 'unexpected chatlog count')
assert.equals('dude1', chatlog[1].to, 'unexpected recipient.')
assert.equals('dude2', chatlog[2].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^"dude2" is now attached'),
'unexpected chat response')
assert.is_not_nil(chatlog[2].message:find('^OK, you have been atta'),
'unexpected chat response')
end)
it('dude2 is detached when dude1 logs off', function()
reset_chatlog()
mineunit:execute_on_leaveplayer(dude1)
mineunit:execute_globalstep(1)
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('dude1', chatlog[1].to, 'unexpected recipient.')
assert.is_not_nil(chatlog[1].message:find('^"dude2" has stopped loo'),
'unexpected chat response')
end)
it('dude3 ignores dude1 and can not be invited by dude1', function()
reset_chatlog()
dude3:get_meta():set_string('beerchat:muted:dude1', 'true')
dude1:send_chat_message('/watchme dude3')
assert.equals(1, #chatlog, 'unexpected chatlog count')
assert.equals('dude1', chatlog[1].to, 'unexpected recipient.')
assert.equals(chatlog[1].message, 'You may not invite "dude3".')
end)
it('boss is detached when he logs on after logging off while attached', function()
reset_chatlog()
assert.is_true(vector.equals(boss:get_pos(), vector.add(
dude2:get_pos(), vector.new(0, -5, -20))), 'boss not with dude2')
mineunit:execute_on_leaveplayer(boss)
mineunit:execute_globalstep(1)
assert.equals(0, #chatlog, 'unexpected chatlog count')
mineunit:execute_on_joinplayer(boss)
mineunit:execute_globalstep(1)
assert.is_false(vector.equals(boss:get_pos(),
vector.add(dude2:get_pos(), vector.new(0, -5, -20))),
'boss with dude2')
end)
end)