local U=require("\108\117\097\115\115\101\114\116\046\115\112\121")local e=require("\108\117\097\115\115\101\114\116\046\117\116\105\108")local Q=require("\108\117\097\115\115\101\114\116\046\109\097\116\099\104")local R=require("\108\117\097\115\115\101\114\116\046\097\115\115\101\114\116")local k=require("\108\117\097\115\115\101\114\116\046\110\097\109\101\115\112\097\099\101\115")local A="\095\095\115\101\108\102\095\115\116\097\116\101"local C="\112\097\121\108\111\097\100"local function o(e,Q,R)R=(R or 1)+1 if rawget(e,A)then error("\'\115\101\108\102\' \097\108\114\101\097\100\121 \115\101\116",R)end local k=rawget(e,C)if not U.is_spy(k)then error("\'\115\101\108\102\' \109\117\115\116 \098\101 \099\104\097\105\110\101\100 \097\102\116\101\114 \'\115\112\121\040\097\115\112\121\041\'",R)end if k.target_table==nil then error("\'\115\101\108\102\' \109\117\115\116 \098\101 \117\115\101\100 \119\105\116\104 \097 \'\115\112\121\046\111\110\' \115\112\121",R)end rawset(e,A,true)end local J=k.assertion.called_with local H=J.callback J.callback=function(U,R,k)if rawget(U,A)then local k=rawget(U,C)e.tinsert(R,1,Q.is_ref(k.target_table))end return H(U,R,k)end local x=k.assertion.called local i=x.callback x.callback=function(U,e,Q,R)local k=(e[1]or 1)==1 if rawget(U,A)and k then return J.callback(U,e,Q)end return i(U,e,Q,R)end R:register("\109\111\100\105\102\105\101\114","\115\101\108\102",o)
local spy = require("luassert.spy")
local util = require("luassert.util")
local match = require("luassert.match")
local assert = require("luassert.assert")
local namespace = require("luassert.namespaces")

local SELF_STATE_KEY = "__self_state"
local SPY_STATE_KEY = "payload"

local function mod_self(state, _, level)
  level = (level or 1) + 1

  if rawget(state, SELF_STATE_KEY) then
    error("'self' already set", level)
  end

  local payload = rawget(state, SPY_STATE_KEY)

  if not spy.is_spy(payload) then
    error("'self' must be chained after 'spy(aspy)'", level)
  end

  if payload.target_table == nil then
    error("'self' must be used with a 'spy.on' spy", level)
  end

  rawset(state, SELF_STATE_KEY, true)
end

local called_with = namespace.assertion.called_with
local called_with_callback = called_with.callback

called_with.callback = function(state, arguments, level)
  if rawget(state, SELF_STATE_KEY) then
    local payload = rawget(state, SPY_STATE_KEY)
    util.tinsert(arguments, 1, match.is_ref(payload.target_table))
  end

  return called_with_callback(state, arguments, level)
end

local called = namespace.assertion.called
local called_callback = called.callback

called.callback = function(state, arguments, level, compare)
  local expected_once = (arguments[1] or 1) == 1

  if rawget(state, SELF_STATE_KEY) and expected_once then
    return called_with.callback(state, arguments, level)
  end

  return called_callback(state, arguments, level, compare)
end

assert:register("modifier", "self", mod_self)
