local format_message = require 'std.dbg.format' describe( 'std.dbg.format', function () describe( '{N} basic indexing', function () it( 'should resolve {1}', function () local result = format_message( 'test {1}', { 'hello' } ) assert.equal( 'test hello', result ) end ) it( 'should resolve {2}', function () local result = format_message( 'test {2}', { 'first', 'second' } ) assert.equal( 'test second', result ) end ) it( 'should resolve multiple indices', function () local result = format_message( '{1} {2}', { 'A', 'B' } ) assert.equal( 'A B', result ) end ) it( 'should resolve reversed order', function () local result = format_message( '{2} {1}', { 'A', 'B' } ) assert.equal( 'B A', result ) end ) it( 'should resolve with literals mixed in', function () local result = format_message( 'prefix {1} middle {2} suffix', { 'a', 'b' } ) assert.equal( 'prefix a middle b suffix', result ) end ) it( 'should allow same index multiple times', function () local result = format_message( '{1} + {1}', { 'five' } ) assert.equal( 'five + five', result ) end ) it( 'should error for missing index on non-array table', function () local ok, err = pcall( function () format_message( '{1}', { name = 'value' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) end ) it( 'should error when {N} exceeds data', function () local ok, err = pcall( function () format_message( '{3}', { 'a', 'b' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) assert.is_not_nil( tostring( err ):find 'did you mean' ) end ) it( 'should error when {1} on empty data', function () local ok, err = pcall( function () format_message( '{1}', {} ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) end ) it( 'should error on empty placeholder', function () local ok, err = pcall( function () format_message( '{}', { 'x' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'not allowed' ) end ) it( 'should error when first key is not numeric', function () local ok, err = pcall( function () format_message( '{name}', { name = 'value' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'must be a numeric index' ) end ) end ) describe( '{0} all data', function () it( 'should resolve {0} on table', function () local result = format_message( '{0}', { a = 1, b = 'bee' } ) assert.is_string( result ) assert.is_not_nil( result:find 'a' ) assert.is_not_nil( result:find 'b' ) end ) it( 'should resolve {0} multiple times', function () local result = format_message( '{0} and {0}', { x = 1 } ) local parts = vim.split( result, ' and ' ) assert.equal( 2, #parts ) end ) it( 'should error when {0} followed by keys', function () local ok, err = pcall( function () format_message( '{0.key}', { a = 1 } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'cannot be followed' ) end ) end ) describe( '{N.key} chained access', function () it( 'should resolve {1.a} on single table wrapped', function () local result = format_message( 'test {1.a}', { { a = 'hello' } } ) assert.equal( 'test hello', result ) end ) it( 'should resolve {2.b} with multiple varargs', function () local result = format_message( 'test {2.b}', { 'x', { b = 'y' } } ) assert.equal( 'test y', result ) end ) it( 'should resolve {1.a} and {2.b}', function () local result = format_message( '{1.a} {2.b}', { { a = 1 }, { b = 2 } } ) assert.equal( '1 2', result ) end ) it( 'should resolve deeply chained {1.a.b}', function () local result = format_message( '{1.a.b}', { { a = { b = 'deep' } } } ) assert.equal( 'deep', result ) end ) it( 'should resolve {1.1} on array inside vararg', function () local result = format_message( '{1.1}', { { 'first', 'second' } } ) assert.equal( 'first', result ) end ) it( 'should resolve {1.2} on array inside vararg', function () local result = format_message( '{1.2}', { { 'first', 'second', 'third' } } ) assert.equal( 'second', result ) end ) it( 'should resolve {1.1.name} nested', function () local result = format_message( '{1.1.name}', { { { name = 'nested' } } } ) assert.equal( 'nested', result ) end ) it( 'should resolve complex chain {2.1.jan.name}', function () local result = format_message( '{2.1.jan.name}', { 'x', { age = 39, { jan = { name = 'jan', age = 11 } } } } ) assert.equal( 'jan', result ) end ) it( 'should resolve complex chain {2.1.jan.age}', function () local result = format_message( '{2.1.jan.age}', { 'x', { age = 39, { jan = { name = 'jan', age = 11 } } } } ) assert.equal( '11', result ) end ) it( 'should error for missing chained key', function () local ok, err = pcall( function () format_message( '{1.z}', { { a = 'hello' } } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'not found' ) end ) it( 'should error when indexing into non-table', function () local ok, err = pcall( function () format_message( '{1.a}', { 'string' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'not found' ) end ) it( 'should error when {N} index has no value', function () local ok, err = pcall( function () format_message( '{1.a}', { a = 'hello' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) end ) end ) describe( '{N.["key"]} bracket notation', function () describe( 'happy path', function () it( 'should resolve dot in key via {1.["a.b"]}', function () local result = format_message( '{1.["a.b"]}', { { ['a.b'] = 1 } } ) assert.equal( '1', result ) end ) it( 'should resolve numeric string key via {1.["1"]}', function () local result = format_message( '{1.["1"]}', { { ['1'] = 'str' } } ) assert.equal( 'str', result ) end ) it( 'should resolve whitespace key via {1.[" spaces "]', function () local result = format_message( '{1.[" spaces "]}', { { [' spaces '] = '#' } } ) assert.equal( '#', result ) end ) it( 'should resolve reserved keyword via {1.["function"]}', function () local result = format_message( '{1.["function"]}', { { ['function'] = 2 } } ) assert.equal( '2', result ) end ) it( 'should resolve empty string key via {1.[""]}', function () local result = format_message( '{1.[""]}', { { [''] = 'empty' } } ) assert.equal( 'empty', result ) end ) it( 'should resolve single-quoted key via {1.["my key"]}', function () local result = format_message( "{1.['my key']}", { { ['my key'] = 'v' } } ) assert.equal( 'v', result ) end ) it( 'should resolve mixed bare and bracket via {1.a.["x.y"].z}', function () local t = { a = { ['x.y'] = { z = 'ok' } } } local result = format_message( '{1.a.["x.y"].z}', { t } ) assert.equal( 'ok', result ) end ) it( 'should resolve multiple consecutive brackets via {1.["a b"].["c d"]}', function () local t = { ['a b'] = { ['c d'] = 'deep' } } local result = format_message( '{1.["a b"].["c d"]}', { t } ) assert.equal( 'deep', result ) end ) it( 'should resolve bracket key as first after N via {1.["hello world"]}', function () local result = format_message( '{1.["hello world"]}', { { ['hello world'] = 'hw' } } ) assert.equal( 'hw', result ) end ) it( 'should resolve unicode in bracket via {1.["日本 語"]}', function () local result = format_message( '{1.["日本 語"]}', { { ['日本 語'] = 'jp' } } ) assert.equal( 'jp', result ) end ) end ) describe( 'disambiguation', function () it( 'should distinguish ["2"] (string key) from .2 (integer key)', function () local t = { [2] = 'integer', ['2'] = 'string' } local result = format_message( '{1.["2"]}', { t } ) assert.equal( 'string', result ) end ) end ) describe( 'error cases', function () it( 'should error on unclosed bracket', function () local ok, err = pcall( function () format_message( '{1.["key}', { 'x' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'parse' ) end ) it( 'should error on empty brackets', function () local ok, err = pcall( function () format_message( '{1.[]}', { 'x' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'parse' ) end ) it( 'should error on missing quote', function () local ok, err = pcall( function () format_message( '{1.[key]}', { 'x' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'parse' ) end ) it( 'should error on key not found via bracket', function () local ok, err = pcall( function () format_message( '{1.["missing"]}', { { a = 1 } } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'not found' ) end ) end ) end ) describe( 'table values', function () it( 'should vim.inspect a Table', function () local result = format_message( '{1}', { { a = 1, b = 2 } } ) assert.is_string( result ) assert.is_not_nil( result:find 'a' ) assert.is_not_nil( result:find 'b' ) end ) it( 'should vim.inspect nested tables', function () local result = format_message( '{1}', { { { deep = true } } } ) assert.is_string( result ) assert.is_not_nil( result:find 'deep' ) end ) end ) describe( 'primitive types', function () it( 'should convert numbers to strings', function () local result = format_message( '{1}', { 42 } ) assert.equal( '42', result ) end ) it( 'should convert booleans to strings', function () local result = format_message( '{1}', { true } ) assert.equal( 'true', result ) end ) it( 'should convert false to strings', function () local result = format_message( '{1}', { false } ) assert.equal( 'false', result ) end ) end ) describe( 'index edge cases', function () it( 'should error for negative index', function () local ok, err = pcall( function () format_message( '{-1}', { 'value' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) end ) it( 'should error for zero index on empty data', function () local ok, err = pcall( function () format_message( '{0}', {} ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'empty data' ) end ) it( 'should error for non-integer index', function () local ok, err = pcall( function () format_message( '{1}', { 'value' } ) end ) assert.is_true( ok ) end ) it( 'should error for very large index', function () local ok, err = pcall( function () format_message( '{999999}', { 'value' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) end ) end ) describe( 'key edge cases', function () it( 'should handle long key names', function () local longkey = string.rep( 'a', 1000 ) local result = format_message( '{1.' .. longkey .. '}', { { [longkey] = 'longvalue' } } ) assert.equal( 'longvalue', result ) end ) it( 'should handle unicode keys', function () local result = format_message( '{1.日本語}', { { ['日本語'] = 'japanese' } } ) assert.equal( 'japanese', result ) end ) it( 'should handle alternating numeric and string keys deeply', function () local t = { a = { 1, { b = { 1, { c = 'deep' } } } } } local result = format_message( '{1.a.2.b.2.c}', { t } ) assert.equal( 'deep', result ) end ) end ) describe( 'format string edge cases', function () it( 'should handle very long format string', function () local literal = string.rep( 'x', 10000 ) local result = format_message( literal .. '{1}' .. literal, { 'Y' } ) assert.equal( literal .. 'Y' .. literal, result ) end ) it( 'should handle many placeholders in one format', function () local parts = {} local expected = {} for i = 1, 100 do parts[i] = '{' .. i .. '}' expected[i] = tostring( i ) end local data = {} for i = 1, 100 do data[i] = i end local result = format_message( table.concat( parts, ' ' ), data ) assert.equal( table.concat( expected, ' ' ), result ) end ) it( 'should handle consecutive placeholders with no separator', function () local result = format_message( '{1}{2}{3}', { 'A', 'B', 'C' } ) assert.equal( 'ABC', result ) end ) end ) describe( 'deep structures', function () it( 'should handle deeply nested tables (3 levels)', function () local t = { level = 1 } for i = 2, 3 do t = { level = i, nested = t } end t = { t } local result = format_message( '{1.nested.nested.level}', t ) assert.equal( '1', result ) end ) it( 'should handle deeply nested tables (10 levels)', function () local t = {} for i = 1, 10 do t = { level = i, nested = t } end t = { t } local result = format_message( '{1' .. string.rep( '.nested', 9 ) .. '.level}', t ) assert.equal( '1', result ) end ) end ) describe( 'edge cases', function () it( 'should return empty string for empty format', function () local result = format_message( '', {} ) assert.equal( '', result ) end ) it( 'should return format unchanged when no placeholders', function () local result = format_message( 'no placeholders here', { 'ignored' } ) assert.equal( 'no placeholders here', result ) end ) it( 'should handle placeholder at start and end', function () local result = format_message( '{1} middle {2}', { 'first', 'last' } ) assert.equal( 'first middle last', result ) end ) it( 'should handle consecutive placeholders', function () local result = format_message( '{1}{2}{3}', { 'A', 'B', 'C' } ) assert.equal( 'ABC', result ) end ) end ) describe( 'levenshtein()', function () local lev = format_message.levenshtein it( 'returns 0 for identical strings', function () assert.equal( 0, lev( 'hello', 'hello' ) ) assert.equal( 0, lev( '', '' ) ) assert.equal( 0, lev( 'a', 'a' ) ) end ) it( 'returns length difference for empty string', function () assert.equal( 3, lev( '', 'abc' ) ) assert.equal( 3, lev( 'abc', '' ) ) end ) it( 'returns 1 for single character difference', function () assert.equal( 1, lev( 'cat', 'car' ) ) assert.equal( 1, lev( 'name', 'nam' ) ) assert.equal( 1, lev( 'name', 'names' ) ) end ) it( 'returns 2 for swapped characters', function () assert.equal( 2, lev( 'name', 'nmae' ) ) assert.equal( 2, lev( 'cat', 'act' ) ) end ) it( 'handles kitten vs sitting (distance 3)', function () assert.equal( 3, lev( 'kitten', 'sitting' ) ) end ) it( 'returns correct distances for various pairs', function () assert.equal( 1, lev( 'foo', 'fo' ) ) assert.equal( 1, lev( 'foo', 'fOo' ) ) assert.equal( 4, lev( 'hello', 'world' ) ) end ) end ) describe( 'key not found errors', function () it( 'suggests close key for typo in key name', function () local ok, err = pcall( function () format_message( '{1.namme}', { { name = 'hi' } } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'Key not found' ) assert.is_not_nil( tostring( err ):find "did you mean 'name'" ) end ) it( 'suggests from multiple keys', function () local ok, err = pcall( function () format_message( '{1.ags}', { { age = 10, name = 'bob' } } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'Key not found' ) assert.is_not_nil( tostring( err ):find "did you mean 'age'" ) end ) it( 'suggests correct key for minor typo', function () local ok, err = pcall( function () format_message( '{1.nam}', { { name = 'bob' } } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'Key not found' ) assert.is_not_nil( tostring( err ):find "did you mean 'name'" ) end ) it( 'does not suggest when key is too different', function () local ok, err = pcall( function () format_message( '{1.xyz}', { { name = 'bob' } } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'Key not found' ) assert.is_nil( tostring( err ):find 'did you mean' ) end ) it( 'suggests in deeply nested path', function () local ok, err = pcall( function () format_message( '{1.a.nmae}', { { a = { name = 'nested' } } } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'Key not found' ) assert.is_not_nil( tostring( err ):find "did you mean 'name'" ) end ) it( 'index suggestion still works when index exceeds data', function () local ok, err = pcall( function () format_message( '{3}', { 'a', 'b' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) assert.is_not_nil( tostring( err ):find 'did you mean {2}' ) end ) it( 'no index suggestion when too far out of range', function () local ok, err = pcall( function () format_message( '{6}', { 'a', 'b' } ) end ) assert.is_false( ok ) assert.is_not_nil( tostring( err ):find 'out of range' ) assert.is_nil( tostring( err ):find 'did you mean' ) end ) end ) end )