Files
avante.nvim/tests/utils/streaming_json_parser_spec.lua
2025-04-30 03:07:18 +08:00

224 lines
7.1 KiB
Lua

local StreamingJSONParser = require("avante.utils.streaming_json_parser")
describe("StreamingJSONParser", function()
local parser
before_each(function() parser = StreamingJSONParser:new() end)
describe("initialization", function()
it("should create a new parser with empty state", function()
assert.is_not_nil(parser)
assert.equals("", parser.buffer)
assert.is_not_nil(parser.state)
assert.is_false(parser.state.inString)
assert.is_false(parser.state.escaping)
assert.is_table(parser.state.stack)
assert.equals(0, #parser.state.stack)
assert.is_nil(parser.state.result)
assert.is_nil(parser.state.currentKey)
assert.is_nil(parser.state.current)
assert.is_table(parser.state.parentKeys)
end)
end)
describe("parse", function()
it("should parse a complete simple JSON object", function()
local result, complete = parser:parse('{"key": "value"}')
assert.is_true(complete)
assert.is_table(result)
assert.equals("value", result.key)
end)
it("should parse breaklines", function()
local result, complete = parser:parse('{"key": "value\nv"}')
assert.is_true(complete)
assert.is_table(result)
assert.equals("value\nv", result.key)
end)
it("should parse a complete simple JSON array", function()
local result, complete = parser:parse("[1, 2, 3]")
assert.is_true(complete)
assert.is_table(result)
assert.equals(1, result[1])
assert.equals(2, result[2])
assert.equals(3, result[3])
end)
it("should handle streaming JSON in multiple chunks", function()
local result1, complete1 = parser:parse('{"name": "John')
assert.is_false(complete1)
assert.is_table(result1)
assert.equals("John", result1.name)
local result2, complete2 = parser:parse('", "age": 30}')
assert.is_true(complete2)
assert.is_table(result2)
assert.equals("John", result2.name)
assert.equals(30, result2.age)
end)
it("should handle streaming string field", function()
local result1, complete1 = parser:parse('{"name": {"first": "John')
assert.is_false(complete1)
assert.is_table(result1)
assert.equals("John", result1.name.first)
end)
it("should parse nested objects", function()
local json = [[{
"person": {
"name": "John",
"age": 30,
"address": {
"city": "New York",
"zip": "10001"
}
}
}]]
local result, complete = parser:parse(json)
assert.is_true(complete)
assert.is_table(result)
assert.is_table(result.person)
assert.equals("John", result.person.name)
assert.equals(30, result.person.age)
assert.is_table(result.person.address)
assert.equals("New York", result.person.address.city)
assert.equals("10001", result.person.address.zip)
end)
it("should parse nested arrays", function()
local json = [[{
"matrix": [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
}]]
local result, complete = parser:parse(json)
assert.is_true(complete)
assert.is_table(result)
assert.is_table(result.matrix)
assert.equals(3, #result.matrix)
assert.equals(1, result.matrix[1][1])
assert.equals(5, result.matrix[2][2])
assert.equals(9, result.matrix[3][3])
end)
it("should handle boolean values", function()
local result, complete = parser:parse('{"success": true, "failed": false}')
assert.is_true(complete)
assert.is_table(result)
assert.is_true(result.success)
assert.is_false(result.failed)
end)
it("should handle null values", function()
local result, complete = parser:parse('{"value": null}')
assert.is_true(complete)
assert.is_table(result)
assert.is_nil(result.value)
end)
it("should handle escaped characters in strings", function()
local result, complete = parser:parse('{"text": "line1\\nline2\\t\\"quoted\\""}')
assert.is_true(complete)
assert.is_table(result)
assert.equals('line1\nline2\t"quoted"', result.text)
end)
it("should handle numbers correctly", function()
local result, complete = parser:parse('{"integer": 42, "float": 3.14, "negative": -10, "exponent": 1.2e3}')
assert.is_true(complete)
assert.is_table(result)
assert.equals(42, result.integer)
assert.equals(3.14, result.float)
assert.equals(-10, result.negative)
assert.equals(1200, result.exponent)
end)
it("should handle streaming complex JSON", function()
local chunks = {
'{"data": [{"id": 1, "info": {"name":',
' "Product A", "active": true}}, {"id": 2, ',
'"info": {"name": "Product B", "active": false',
'}}], "total": 2}',
}
local complete = false
local result
for _, chunk in ipairs(chunks) do
result, complete = parser:parse(chunk)
end
assert.is_true(complete)
assert.is_table(result)
assert.equals(2, #result.data)
assert.equals(1, result.data[1].id)
assert.equals("Product A", result.data[1].info.name)
assert.is_true(result.data[1].info.active)
assert.equals(2, result.data[2].id)
assert.equals("Product B", result.data[2].info.name)
assert.is_false(result.data[2].info.active)
assert.equals(2, result.total)
end)
it("should reset the parser state correctly", function()
parser:parse('{"key": "value"}')
parser:reset()
assert.equals("", parser.buffer)
assert.is_false(parser.state.inString)
assert.is_false(parser.state.escaping)
assert.is_table(parser.state.stack)
assert.equals(0, #parser.state.stack)
assert.is_nil(parser.state.result)
assert.is_nil(parser.state.currentKey)
assert.is_nil(parser.state.current)
assert.is_table(parser.state.parentKeys)
end)
it("should return partial results for incomplete JSON", function()
parser:reset()
local result, complete = parser:parse('{"stream": [1, 2,')
assert.is_false(complete)
assert.is_table(result)
assert.is_table(result.stream)
assert.equals(1, result.stream[1])
assert.equals(2, result.stream[2])
-- We need exactly one item in the stack (the array)
assert.equals(2, #parser.state.stack)
end)
it("should handle whitespace correctly", function()
parser:reset()
local result, complete = parser:parse('{"key1": "value1", "key2": 42}')
assert.is_true(complete)
assert.is_table(result)
assert.equals("value1", result.key1)
assert.equals(42, result.key2)
end)
it("should provide access to partial results during streaming", function()
parser:parse('{"name": "John", "items": [')
local partial = parser:getCurrentPartial()
assert.is_table(partial)
assert.equals("John", partial.name)
assert.is_table(partial.items)
parser:parse("1, 2]")
local result, complete = parser:parse("}")
assert.is_true(complete)
assert.equals("John", result.name)
assert.equals(1, result.items[1])
assert.equals(2, result.items[2])
end)
end)
end)