Files
BigChef/processor/xml_test.go

346 lines
9.9 KiB
Go

package processor
import (
"strings"
"testing"
"github.com/antchfx/xmlquery"
)
func TestXMLProcessor_Process_TextNodes(t *testing.T) {
// Test XML file with price tags that we want to modify
testXML := `<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
</book>
</catalog>`
// Create an XML processor
processor := NewXMLProcessor(&TestLogger{})
// Process the XML content directly to double all prices
xpathExpr := "//price/text()"
modifiedXML, modCount, matchCount, err := processor.ProcessContent(testXML, xpathExpr, "v1 = v1 * 2", "*2")
if err != nil {
t.Fatalf("Failed to process XML content: %v", err)
}
// Check that we found and modified the correct number of nodes
if matchCount != 2 {
t.Errorf("Expected to match 2 nodes, got %d", matchCount)
}
if modCount != 2 {
t.Errorf("Expected to modify 2 nodes, got %d", modCount)
}
// Check that prices were doubled
if !strings.Contains(modifiedXML, "<price>89.9</price>") {
t.Errorf("Modified content does not contain doubled price 89.9")
}
if !strings.Contains(modifiedXML, "<price>11.9</price>") {
t.Errorf("Modified content does not contain doubled price 11.9")
}
// Verify we can parse the XML after modification
_, err = xmlquery.Parse(strings.NewReader(modifiedXML))
if err != nil {
t.Errorf("Modified XML is not valid: %v", err)
}
}
func TestXMLProcessor_Process_Elements(t *testing.T) {
// Test XML file with elements that we want to modify attributes of
testXML := `<?xml version="1.0" encoding="UTF-8"?>
<items>
<item id="1" value="100" />
<item id="2" value="200" />
<item id="3" value="300" />
</items>`
// Create an XML processor
processor := NewXMLProcessor(&TestLogger{})
// Process the file to modify the value attribute
// We'll create a more complex Lua script that deals with the node table
luaScript := `
-- Get the current value attribute
local valueAttr = node.attributes.value
if valueAttr then
-- Convert to number and add 50
local numValue = tonumber(valueAttr)
if numValue then
-- Update the value in the attributes table
node.attributes.value = tostring(numValue + 50)
end
end
`
// Process the XML content directly
xpathExpr := "//item"
modifiedXML, modCount, matchCount, err := processor.ProcessContent(testXML, xpathExpr, luaScript, "Add 50 to values")
if err != nil {
t.Fatalf("Failed to process XML content: %v", err)
}
// Check that we found and modified the correct number of nodes
if matchCount != 3 {
t.Errorf("Expected to match 3 item nodes, got %d", matchCount)
}
if modCount != 3 {
t.Errorf("Expected to modify 3 nodes, got %d", modCount)
}
// Check that values were increased by 50
if !strings.Contains(modifiedXML, `value="150"`) {
t.Errorf("Modified content does not contain updated value 150")
}
if !strings.Contains(modifiedXML, `value="250"`) {
t.Errorf("Modified content does not contain updated value 250")
}
if !strings.Contains(modifiedXML, `value="350"`) {
t.Errorf("Modified content does not contain updated value 350")
}
// Verify we can parse the XML after modification
_, err = xmlquery.Parse(strings.NewReader(modifiedXML))
if err != nil {
t.Errorf("Modified XML is not valid: %v", err)
}
}
// New test for adding attributes to XML elements
func TestXMLProcessor_AddAttributes(t *testing.T) {
testXML := `<?xml version="1.0" encoding="UTF-8"?>
<root>
<element>Content</element>
<element>Another</element>
</root>`
processor := NewXMLProcessor(&TestLogger{})
// Add a new attribute to each element
luaScript := `
-- Add a new attribute
node.attributes.status = "active"
-- Also add another attribute with a sequential number
node.attributes.index = tostring(_POSITION)
`
xpathExpr := "//element"
modifiedXML, modCount, matchCount, err := processor.ProcessContent(testXML, xpathExpr, luaScript, "Add attributes")
if err != nil {
t.Fatalf("Failed to process XML content: %v", err)
}
// Check counts
if matchCount != 2 {
t.Errorf("Expected to match 2 nodes, got %d", matchCount)
}
if modCount != 2 {
t.Errorf("Expected to modify 2 nodes, got %d", modCount)
}
// Verify the new attributes
if !strings.Contains(modifiedXML, `status="active"`) {
t.Errorf("Modified content does not contain added status attribute")
}
if !strings.Contains(modifiedXML, `index="1"`) && !strings.Contains(modifiedXML, `index="2"`) {
t.Errorf("Modified content does not contain added index attributes")
}
// Verify the XML is valid
_, err = xmlquery.Parse(strings.NewReader(modifiedXML))
if err != nil {
t.Errorf("Modified XML is not valid: %v", err)
}
}
// Test for adding new child elements
func TestXMLProcessor_AddChildElements(t *testing.T) {
testXML := `<?xml version="1.0" encoding="UTF-8"?>
<products>
<product id="1">
<name>Product One</name>
<price>10.99</price>
</product>
<product id="2">
<name>Product Two</name>
<price>20.99</price>
</product>
</products>`
processor := NewXMLProcessor(&TestLogger{})
// Add a new child element to each product
luaScript := `
-- Create a new "discount" child element
local discount = create_node("discount")
-- Calculate discount as 10% of price
local priceText = ""
for _, child in ipairs(node.children) do
if child.name == "price" and child.children[1] then
priceText = child.children[1].data
break
end
end
local price = tonumber(priceText) or 0
local discountValue = price * 0.1
-- Add text content to the discount element
discount.children[1] = {type="text", data=string.format("%.2f", discountValue)}
-- Add the new element as a child
add_child(node, discount)
`
xpathExpr := "//product"
modifiedXML, modCount, matchCount, err := processor.ProcessContent(testXML, xpathExpr, luaScript, "Add discount elements")
if err != nil {
t.Fatalf("Failed to process XML content: %v", err)
}
// Check counts
if matchCount != 2 {
t.Errorf("Expected to match 2 nodes, got %d", matchCount)
}
if modCount != 2 {
t.Errorf("Expected to modify 2 nodes, got %d", modCount)
}
// Verify the new elements
if !strings.Contains(modifiedXML, "<discount>1.10</discount>") {
t.Errorf("Modified content does not contain first discount element")
}
if !strings.Contains(modifiedXML, "<discount>2.10</discount>") {
t.Errorf("Modified content does not contain second discount element")
}
// Verify the XML is valid
_, err = xmlquery.Parse(strings.NewReader(modifiedXML))
if err != nil {
t.Errorf("Modified XML is not valid: %v", err)
}
}
// Test for complex XML transformations
func TestXMLProcessor_ComplexTransformation(t *testing.T) {
testXML := `<?xml version="1.0" encoding="UTF-8"?>
<config>
<settings>
<setting name="timeout" value="30" />
<setting name="retries" value="3" />
<setting name="enabled" value="true" />
</settings>
</config>`
processor := NewXMLProcessor(&TestLogger{})
// Complex transformation that changes attributes based on name
luaScript := `
local name = node.attributes.name
local value = node.attributes.value
if name == "timeout" then
-- Double the timeout
node.attributes.value = tostring(tonumber(value) * 2)
-- Add a unit attribute
node.attributes.unit = "seconds"
elseif name == "retries" then
-- Increase retries by 2
node.attributes.value = tostring(tonumber(value) + 2)
-- Add a comment element as sibling
local comment = create_node("comment")
comment.children[1] = {type="text", data="Increased for reliability"}
-- We can't directly add siblings in this implementation
-- But this would be the place to do it if supported
elseif name == "enabled" and value == "true" then
-- Add a priority attribute for enabled settings
node.attributes.priority = "high"
end
`
xpathExpr := "//setting"
modifiedXML, _, matchCount, err := processor.ProcessContent(testXML, xpathExpr, luaScript, "Transform settings")
if err != nil {
t.Fatalf("Failed to process XML content: %v", err)
}
// Check counts
if matchCount != 3 {
t.Errorf("Expected to match 3 nodes, got %d", matchCount)
}
// Verify the transformed attributes
if !strings.Contains(modifiedXML, `value="60"`) {
t.Errorf("Modified content does not have doubled timeout value")
}
if !strings.Contains(modifiedXML, `unit="seconds"`) {
t.Errorf("Modified content does not have added unit attribute")
}
if !strings.Contains(modifiedXML, `value="5"`) {
t.Errorf("Modified content does not have increased retries value")
}
if !strings.Contains(modifiedXML, `priority="high"`) {
t.Errorf("Modified content does not have added priority attribute")
}
// Verify the XML is valid
_, err = xmlquery.Parse(strings.NewReader(modifiedXML))
if err != nil {
t.Errorf("Modified XML is not valid: %v", err)
}
}
// Test for handling special XML characters
func TestXMLProcessor_SpecialCharacters(t *testing.T) {
testXML := `<?xml version="1.0" encoding="UTF-8"?>
<data>
<item><![CDATA[Special & <characters> "here"]]></item>
<item>Regular & text with <b>markup</b></item>
</data>`
processor := NewXMLProcessor(&TestLogger{})
// Process text nodes, being careful with special characters
luaScript := `
-- For text nodes, replace & with &amp;
s1 = string.gsub(s1, "&([^;])", "&amp;%1")
`
xpathExpr := "//item/text()"
modifiedXML, _, _, err := processor.ProcessContent(testXML, xpathExpr, luaScript, "Handle special chars")
if err != nil {
t.Fatalf("Failed to process XML content: %v", err)
}
// CDATA sections should be preserved
if !strings.Contains(modifiedXML, "<![CDATA[") {
t.Errorf("CDATA section was not preserved")
}
// Verify the XML is valid
_, err = xmlquery.Parse(strings.NewReader(modifiedXML))
if err != nil {
t.Errorf("Modified XML is not valid: %v", err)
}
}