Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/tests/bugabinga/pivi/backfill_spec.lua

Raw
---@diagnostic disable: duplicate-set-field, need-check-nil, param-type-mismatch, assign-type-mismatch
local backfill = require 'bugabinga.pivi.backfill'

local entries = function( list ) return { entries = list, } end

local message = function( role, content, extra )
  return { type = 'message', message = vim.tbl_extend( 'force', { role = role, content = content, }, extra or {} ), }
end

describe( 'pivi backfill', function()
  it( 'plans nothing from empty or malformed history', function()
    assert.same( {}, backfill.plan( nil ) )
    assert.same( {}, backfill.plan( {} ) )
    assert.same( {}, backfill.plan( entries { { type = 'model_change', }, } ) )
  end )

  it( 'selects leaf ancestry before correlating tool results, including metadata ancestors', function()
    local call = message( 'assistant', { { type = 'toolCall', id = 'c1', name = 'edit', arguments = {}, }, } )
    call.id, call.parentId = 'call', 'root'
    local discarded = message( 'toolResult', 'discarded', { toolCallId = 'c1', details = { diff = 'wrong', }, } )
    discarded.id, discarded.parentId = 'discarded', 'call'
    local selected = message( 'toolResult', 'selected', { toolCallId = 'c1', details = { diff = 'right', }, } )
    selected.id, selected.parentId = 'selected', 'call'
    local root = message( 'user', 'shared' )
    root.id, root.parentId = 'root', vim.NIL
    local data = { entries = { discarded, selected, call, root, { type = 'session_info', id = 'leaf', parentId = 'selected', }, }, leafId = 'leaf', }
    local ops = backfill.plan( data )
    assert.equal( 2, #ops )
    assert.equal( 'shared', ops[1].text )
    assert.equal( 'selected', ops[2].result.content )
    assert.same( { diff = 'right', }, ops[2].result.details )
    data.leafId = 'call'
    assert.is_nil( backfill.plan( data )[2].result.content )
    assert.equal( 'discarded', data.entries[1].message.content )
  end )

  it( 'renders no history for null leaf, including a populated tree', function()
    assert.same( {}, backfill.plan { entries = {}, leafId = vim.NIL, } )
    assert.same( {}, backfill.plan { entries = { message( 'user', 'discarded' ), }, leafId = vim.NIL, } )
  end )

  it( 'fails closed on missing, malformed, duplicate or cyclic ancestry', function()
    local root = { type = 'message', id = 'root', parentId = vim.NIL, message = { role = 'user', content = 'hidden', }, }
    for _, leaf in ipairs( { 'absent', false, 1, '', {}, } ) do
      assert.same( {}, backfill.plan { entries = { root, }, leafId = leaf, } )
    end
    for _, parent in ipairs( { 'absent', 'root', false, 1, {}, } ) do
      local broken = vim.deepcopy( root )
      broken.parentId = parent
      assert.same( {}, backfill.plan { entries = { broken, }, leafId = 'root', } )
    end
    local missing = vim.deepcopy( root )
    missing.parentId = nil
    assert.equal( 'hidden', backfill.plan( { entries = { missing, }, leafId = 'root', } )[1].text )
    assert.same( {}, backfill.plan { entries = { root, root, }, leafId = 'root', } )
    assert.same( {}, backfill.plan { entries = { root, }, } )
    assert.same( {}, backfill.plan { root, } )
    assert.same( {}, backfill.plan { entries = { root, { id = 'b', parentId = 'c', }, { id = 'c', parentId = 'b', }, }, leafId = 'b', } )
  end )

  it( 'preserves legacy raw idless message fixtures', function()
    assert.equal( 'legacy', backfill.plan( { message( 'user', 'legacy' ), } )[1].text )
  end )

  it( 'turns a user message into a prompt op', function()
    local ops = backfill.plan( entries { message( 'user', 'hello there' ), } )
    assert.equal( 1, #ops )
    assert.equal( 'prompt', ops[1].kind )
    assert.equal( 'hello there', ops[1].text )
  end )

  it( 'reads user text from content parts as well as a bare string', function()
    local ops = backfill.plan( entries {
      message( 'user', { { type = 'text', text = 'part one ', }, { type = 'text', text = 'part two', }, } ),
    } )
    assert.equal( 'part one part two', ops[1].text )
  end )

  it( 'turns assistant text into an answer op', function()
    local ops = backfill.plan( entries {
      message( 'assistant', { { type = 'text', text = 'the answer', }, } ),
    } )
    assert.equal( 'answer', ops[1].kind )
    assert.equal( 'the answer', ops[1].text )
  end )

  it( 'pairs a tool call with its result by call id', function()
    local ops = backfill.plan( entries {
      message( 'assistant', {
        { type = 'tool_call', id = 'c1', name = 'nu', arguments = { command = 'ls', }, },
      } ),
      message( 'toolResult', { { type = 'text', text = 'file.txt', }, }, {
        toolCallId = 'c1', toolName = 'nu', isError = false,
      } ),
    } )

    assert.equal( 1, #ops )
    local call = ops[1]
    assert.equal( 'tool', call.kind )
    assert.equal( 'nu', call.tool )
    assert.equal( 'ls', call.args.command )
    assert.equal( 'c1', call.call )
    assert.same( { { type = 'text', text = 'file.txt', }, }, call.result.content )
    assert.is_false( call.failed )
  end )

  it( 'marks a failed tool result', function()
    local ops = backfill.plan( entries {
      message( 'assistant', { { type = 'tool_call', id = 'c9', name = 'nu', arguments = {}, }, } ),
      message( 'toolResult', { { type = 'text', text = 'boom', }, }, { toolCallId = 'c9', isError = true, } ),
    } )
    assert.is_true( ops[1].failed )
  end )

  it( 'keeps text before and after a tool call as separate answer ops', function()
    local ops = backfill.plan( entries {
      message( 'assistant', {
        { type = 'text', text = 'before', },
        { type = 'tool_call', id = 'c1', name = 'nu', arguments = {}, },
        { type = 'text', text = 'after', },
      } ),
    } )

    assert.equal( 'answer', ops[1].kind )
    assert.equal( 'before', ops[1].text )
    assert.equal( 'tool', ops[2].kind )
    assert.equal( 'answer', ops[3].kind )
    assert.equal( 'after', ops[3].text )
  end )

  it( 'restores native shell output with reported truncation and no fabricated change', function()
    local ops = backfill.plan( entries {
      message( 'bashExecution', nil, {
        command = 'echo hi', output = 'hi', exitCode = 0, truncated = true,
        fullOutputPath = '/tmp/full.log', excludeFromContext = true,
      } ),
    } )
    assert.equal( 'bang!', ops[1].tool )
    assert.equal( 'hi', ops[1].result.content[1].text )
    assert.is_true( ops[1].result.details.truncation.truncated )
    assert.equal( '/tmp/full.log', ops[1].result.details.fullOutputPath )
    assert.is_nil( ops[1].result.details.diff )
    assert.is_false( ops[1].failed )
  end )

  it( 'orders a whole conversation as it happened', function()
    local ops = backfill.plan( entries {
      { type = 'model_change', },
      message( 'user', 'do it' ),
      message( 'assistant', { { type = 'text', text = 'working', }, { type = 'tool_call', id = 'c1', name = 'nu', arguments = {}, }, } ),
      message( 'toolResult', { { type = 'text', text = 'done', }, }, { toolCallId = 'c1', } ),
      message( 'assistant', { { type = 'text', text = 'finished', }, } ),
    } )

    local kinds = vim.tbl_map( function( op ) return op.kind end, ops )
    assert.same( { 'prompt', 'answer', 'tool', 'answer', }, kinds )
  end )
end )