346 lines
9.9 KiB
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 &
|
|
s1 = string.gsub(s1, "&([^;])", "&%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)
|
|
}
|
|
}
|