Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

neovim/tests/std/dbg/format_spec.lua

Raw
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 )