Add comprehensive tests for XML parser functionality
- Introduced benchmark tests for various XML parsing methods, including parsing from strings, bytes, and readers, to evaluate performance. - Added unit tests for the parser interface and validation mechanisms, ensuring robust error handling and validation logic. - Implemented tests for utility functions related to XML processing, enhancing overall test coverage and reliability. - Created a test suite for the TED domain, validating the structure and functionality of contract notices and related entities. - Developed a comprehensive test runner script to facilitate automated testing, coverage analysis, and performance benchmarking for the XML parser package.
This commit is contained in:
@@ -0,0 +1,814 @@
|
||||
package xmlparser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Mock XML data for testing
|
||||
const (
|
||||
validMockXML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="test-123">
|
||||
<name>Test Mock Name</name>
|
||||
<value>Test mock value</value>
|
||||
</MockElement>`
|
||||
|
||||
validMockXMLWithNamespace = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement xmlns="http://test.example.com" id="test-456">
|
||||
<name>Namespaced Mock</name>
|
||||
<value>Namespaced value</value>
|
||||
</MockElement>`
|
||||
|
||||
invalidMockXML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="test-invalid">
|
||||
<name></name>
|
||||
<value>Missing name</value>
|
||||
</MockElement>`
|
||||
|
||||
malformedXML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="malformed">
|
||||
<name>Unclosed tag</name>
|
||||
<value>This will fail</value>
|
||||
</MockElemen>`
|
||||
|
||||
emptyXML = ``
|
||||
|
||||
largeMockXML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="large-test">
|
||||
<name>Large Mock</name>
|
||||
<value>This is a large XML document with nested elements</value>
|
||||
<nested>
|
||||
<level1>
|
||||
<level2>
|
||||
<level3>
|
||||
<level4>
|
||||
<level5>Deep nesting test</level5>
|
||||
</level4>
|
||||
</level3>
|
||||
</level2>
|
||||
</level1>
|
||||
</nested>
|
||||
</MockElement>`
|
||||
|
||||
deeplyNestedXML = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="deep-test">
|
||||
<name>Deep Nesting Test</name>
|
||||
<value>Testing depth limits</value>
|
||||
<level1><level2><level3><level4><level5>
|
||||
<level6><level7><level8><level9><level10>
|
||||
<level11><level12><level13><level14><level15>
|
||||
<level16><level17><level18><level19><level20>Deep</level20></level19></level18></level17></level16>
|
||||
</level15></level14></level13></level12></level11>
|
||||
</level10></level9></level8></level7></level6>
|
||||
</level5></level4></level3></level2></level1>
|
||||
</MockElement>`
|
||||
)
|
||||
|
||||
// errorReader is a mock reader that always returns an error
|
||||
type errorReader struct{}
|
||||
|
||||
func (er errorReader) Read(p []byte) (n int, err error) {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
func TestNewParser(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
options *ParserOptions
|
||||
}{
|
||||
{
|
||||
name: "Default options",
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Custom options",
|
||||
options: &ParserOptions{
|
||||
StrictValidation: false,
|
||||
AllowEmptyElements: false,
|
||||
PreserveWhitespace: true,
|
||||
IgnoreUnknownElements: true,
|
||||
MaxDepth: 50,
|
||||
MaxSize: 1024 * 1024,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := NewParser[MockParsable](tt.options)
|
||||
|
||||
if parser == nil {
|
||||
t.Error("Expected parser to not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify parser type
|
||||
if _, ok := parser.(*GenericParser[MockParsable]); !ok {
|
||||
t.Error("Expected parser to be of type *GenericParser[MockParsable]")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
xmlData string
|
||||
expectError bool
|
||||
expectedID string
|
||||
options *ParserOptions
|
||||
}{
|
||||
{
|
||||
name: "Valid XML",
|
||||
xmlData: validMockXML,
|
||||
expectError: false,
|
||||
expectedID: "test-123",
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Valid XML with namespace",
|
||||
xmlData: validMockXMLWithNamespace,
|
||||
expectError: false,
|
||||
expectedID: "test-456",
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Invalid XML (validation failure)",
|
||||
xmlData: invalidMockXML,
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Malformed XML",
|
||||
xmlData: malformedXML,
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Empty XML",
|
||||
xmlData: emptyXML,
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Large XML",
|
||||
xmlData: largeMockXML,
|
||||
expectError: false,
|
||||
expectedID: "large-test",
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "XML exceeds size limit",
|
||||
xmlData: largeMockXML,
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
options: &ParserOptions{
|
||||
MaxSize: 100, // Very small limit
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Deeply nested XML exceeds depth",
|
||||
xmlData: deeplyNestedXML,
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
options: &ParserOptions{
|
||||
MaxDepth: 10, // Shallow depth limit
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := NewParser[MockParsable](tt.options)
|
||||
result, err := parser.ParseString(tt.xmlData)
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Error("Expected parsing error but got none")
|
||||
}
|
||||
if result != nil {
|
||||
t.Error("Expected result to be nil when error occurs")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected parsing error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
t.Error("Expected result to not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
if result.GetID() != tt.expectedID {
|
||||
t.Errorf("Expected ID '%s', got '%s'", tt.expectedID, result.GetID())
|
||||
}
|
||||
|
||||
// Verify the mock is valid (should pass validation)
|
||||
if err := result.Validate(); err != nil {
|
||||
t.Errorf("Parsed result failed validation: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseBytes(t *testing.T) {
|
||||
xmlData := []byte(validMockXML)
|
||||
parser := NewParser[MockParsable](nil)
|
||||
|
||||
result, err := parser.ParseBytes(xmlData)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected parsing error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
t.Error("Expected result to not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
if result.GetID() != "test-123" {
|
||||
t.Errorf("Expected ID 'test-123', got '%s'", result.GetID())
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
reader io.Reader
|
||||
expectError bool
|
||||
expectedID string
|
||||
}{
|
||||
{
|
||||
name: "Valid reader",
|
||||
reader: strings.NewReader(validMockXML),
|
||||
expectError: false,
|
||||
expectedID: "test-123",
|
||||
},
|
||||
{
|
||||
name: "Error reader",
|
||||
reader: errorReader{},
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
},
|
||||
{
|
||||
name: "Empty reader",
|
||||
reader: strings.NewReader(""),
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := NewParser[MockParsable](nil)
|
||||
result, err := parser.Parse(tt.reader)
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Error("Expected parsing error but got none")
|
||||
}
|
||||
if result != nil {
|
||||
t.Error("Expected result to be nil when error occurs")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected parsing error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
t.Error("Expected result to not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
if result.GetID() != tt.expectedID {
|
||||
t.Errorf("Expected ID '%s', got '%s'", tt.expectedID, result.GetID())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
reader io.Reader
|
||||
expectError bool
|
||||
options *ParserOptions
|
||||
}{
|
||||
{
|
||||
name: "Valid XML",
|
||||
reader: strings.NewReader(validMockXML),
|
||||
expectError: false,
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Malformed XML",
|
||||
reader: strings.NewReader(malformedXML),
|
||||
expectError: true,
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Empty XML",
|
||||
reader: strings.NewReader(""),
|
||||
expectError: true,
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Error reader",
|
||||
reader: errorReader{},
|
||||
expectError: true,
|
||||
options: nil,
|
||||
},
|
||||
{
|
||||
name: "Deeply nested XML exceeds depth",
|
||||
reader: strings.NewReader(deeplyNestedXML),
|
||||
expectError: true,
|
||||
options: &ParserOptions{
|
||||
MaxDepth: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Valid deeply nested XML within limits",
|
||||
reader: strings.NewReader(deeplyNestedXML),
|
||||
expectError: false,
|
||||
options: &ParserOptions{
|
||||
MaxDepth: 100,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := NewParser[MockParsable](tt.options)
|
||||
err := parser.Validate(tt.reader)
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Error("Expected validation error but got none")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected validation error: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWithResult(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
reader io.Reader
|
||||
expectError bool
|
||||
expectedID string
|
||||
expectMetadata bool
|
||||
expectedVersion string
|
||||
expectedEncoding string
|
||||
}{
|
||||
{
|
||||
name: "Valid XML with metadata",
|
||||
reader: strings.NewReader(validMockXML),
|
||||
expectError: false,
|
||||
expectedID: "test-123",
|
||||
expectMetadata: true,
|
||||
expectedVersion: "1.0",
|
||||
expectedEncoding: "UTF-8",
|
||||
},
|
||||
{
|
||||
name: "Valid XML with namespace",
|
||||
reader: strings.NewReader(validMockXMLWithNamespace),
|
||||
expectError: false,
|
||||
expectedID: "test-456",
|
||||
expectMetadata: true,
|
||||
expectedVersion: "1.0",
|
||||
expectedEncoding: "UTF-8",
|
||||
},
|
||||
{
|
||||
name: "Error reader",
|
||||
reader: errorReader{},
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
expectMetadata: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid XML (validation failure)",
|
||||
reader: strings.NewReader(invalidMockXML),
|
||||
expectError: true,
|
||||
expectedID: "",
|
||||
expectMetadata: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := NewParser[MockParsable](nil)
|
||||
|
||||
// Cast to GenericParser to access ParseWithResult
|
||||
genericParser, ok := parser.(*GenericParser[MockParsable])
|
||||
if !ok {
|
||||
t.Error("Expected parser to be of type *GenericParser[MockParsable]")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := genericParser.ParseWithResult(tt.reader)
|
||||
|
||||
if result == nil {
|
||||
t.Error("Expected result to not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Error("Expected parsing error but got none")
|
||||
}
|
||||
if len(result.Errors) == 0 {
|
||||
t.Error("Expected errors in result")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected parsing error: %v", err)
|
||||
}
|
||||
if len(result.Errors) > 0 {
|
||||
t.Errorf("Unexpected errors in result: %v", result.Errors)
|
||||
}
|
||||
}
|
||||
|
||||
if tt.expectMetadata {
|
||||
if result.Metadata == nil {
|
||||
t.Error("Expected metadata to not be nil")
|
||||
} else {
|
||||
if tt.expectedVersion != "" && result.Metadata.Version != tt.expectedVersion {
|
||||
t.Errorf("Expected version '%s', got '%s'", tt.expectedVersion, result.Metadata.Version)
|
||||
}
|
||||
if tt.expectedEncoding != "" && result.Metadata.Encoding != tt.expectedEncoding {
|
||||
t.Errorf("Expected encoding '%s', got '%s'", tt.expectedEncoding, result.Metadata.Encoding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !tt.expectError && result.Data != nil {
|
||||
if result.Data.GetID() != tt.expectedID {
|
||||
t.Errorf("Expected ID '%s', got '%s'", tt.expectedID, result.Data.GetID())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWithInvalidMockData(t *testing.T) {
|
||||
// Create invalid mock data that will pass XML parsing but fail validation
|
||||
invalidMockData := MockParsable{
|
||||
ID: "test-invalid",
|
||||
Name: "Test Name",
|
||||
Value: "test-validation-failure", // This will cause validation to fail
|
||||
Valid: false, // This will cause validation to fail
|
||||
}
|
||||
|
||||
// This test ensures that even if XML parsing succeeds, validation errors are caught
|
||||
xmlData := `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="test-invalid">
|
||||
<name>Test Name</name>
|
||||
<value>test-validation-failure</value>
|
||||
</MockElement>`
|
||||
|
||||
parser := NewParser[MockParsable](nil)
|
||||
result, err := parser.ParseString(xmlData)
|
||||
|
||||
// This should fail during validation, not XML parsing
|
||||
if err == nil {
|
||||
t.Error("Expected validation error but got none")
|
||||
}
|
||||
|
||||
if result != nil {
|
||||
t.Error("Expected result to be nil when validation fails")
|
||||
}
|
||||
|
||||
// Verify the error message contains validation information
|
||||
if !strings.Contains(err.Error(), "validation failed") {
|
||||
t.Errorf("Expected validation error message, got: %v", err)
|
||||
}
|
||||
|
||||
// Test the mock data validation directly
|
||||
validationErr := invalidMockData.Validate()
|
||||
if validationErr == nil {
|
||||
t.Error("Expected direct validation to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrentParsing(t *testing.T) {
|
||||
parser := NewParser[MockParsable](nil)
|
||||
numGoroutines := 10
|
||||
numOperations := 5
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errors := make(chan error, numGoroutines*numOperations)
|
||||
results := make(chan *MockParsable, numGoroutines*numOperations)
|
||||
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func(goroutineID int) {
|
||||
defer wg.Done()
|
||||
|
||||
for j := 0; j < numOperations; j++ {
|
||||
// Use different XML data for each operation
|
||||
xmlData := strings.Replace(validMockXML, "test-123",
|
||||
fmt.Sprintf("test-%d-%d", goroutineID, j), 1)
|
||||
|
||||
result, err := parser.ParseString(xmlData)
|
||||
|
||||
if err != nil {
|
||||
errors <- err
|
||||
} else {
|
||||
results <- result
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errors)
|
||||
close(results)
|
||||
|
||||
// Check for errors
|
||||
errorCount := 0
|
||||
for err := range errors {
|
||||
t.Errorf("Concurrent parsing error: %v", err)
|
||||
errorCount++
|
||||
}
|
||||
|
||||
// Check results
|
||||
resultCount := 0
|
||||
for range results {
|
||||
resultCount++
|
||||
}
|
||||
|
||||
expectedResults := numGoroutines * numOperations
|
||||
if resultCount != expectedResults {
|
||||
t.Errorf("Expected %d results, got %d (errors: %d)", expectedResults, resultCount, errorCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParserOptionsEffects(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
options *ParserOptions
|
||||
xmlData string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "Strict validation enabled",
|
||||
options: &ParserOptions{
|
||||
StrictValidation: true,
|
||||
},
|
||||
xmlData: validMockXML,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Strict validation disabled",
|
||||
options: &ParserOptions{
|
||||
StrictValidation: false,
|
||||
},
|
||||
xmlData: validMockXML,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Very small size limit",
|
||||
options: &ParserOptions{
|
||||
MaxSize: 10, // Very small
|
||||
},
|
||||
xmlData: validMockXML,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Very small depth limit",
|
||||
options: &ParserOptions{
|
||||
MaxDepth: 1, // Very shallow
|
||||
},
|
||||
xmlData: largeMockXML, // Contains nested elements
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
parser := NewParser[MockParsable](tt.options)
|
||||
_, err := parser.ParseString(tt.xmlData)
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Error("Expected parsing error but got none")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected parsing error: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractMetadata(t *testing.T) {
|
||||
parser := NewParser[MockParsable](nil)
|
||||
genericParser, ok := parser.(*GenericParser[MockParsable])
|
||||
if !ok {
|
||||
t.Error("Expected parser to be of type *GenericParser[MockParsable]")
|
||||
return
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
xmlData string
|
||||
expectedVersion string
|
||||
expectedEncoding string
|
||||
expectedNamespace string
|
||||
}{
|
||||
{
|
||||
name: "Standard XML with version and encoding",
|
||||
xmlData: validMockXML,
|
||||
expectedVersion: "1.0",
|
||||
expectedEncoding: "UTF-8",
|
||||
expectedNamespace: "",
|
||||
},
|
||||
{
|
||||
name: "XML with namespace",
|
||||
xmlData: validMockXMLWithNamespace,
|
||||
expectedVersion: "1.0",
|
||||
expectedEncoding: "UTF-8",
|
||||
expectedNamespace: "http://test.example.com",
|
||||
},
|
||||
{
|
||||
name: "XML with single quotes",
|
||||
xmlData: `<?xml version='1.1' encoding='ISO-8859-1'?>
|
||||
<MockElement id="test">
|
||||
<name>Test</name>
|
||||
<value>Value</value>
|
||||
</MockElement>`,
|
||||
expectedVersion: "1.1",
|
||||
expectedEncoding: "ISO-8859-1",
|
||||
expectedNamespace: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
metadata := &XMLMetadata{}
|
||||
err := genericParser.extractMetadata([]byte(tt.xmlData), metadata)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected metadata extraction error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if metadata.Version != tt.expectedVersion {
|
||||
t.Errorf("Expected version '%s', got '%s'", tt.expectedVersion, metadata.Version)
|
||||
}
|
||||
|
||||
if metadata.Encoding != tt.expectedEncoding {
|
||||
t.Errorf("Expected encoding '%s', got '%s'", tt.expectedEncoding, metadata.Encoding)
|
||||
}
|
||||
|
||||
if metadata.Namespace != tt.expectedNamespace {
|
||||
t.Errorf("Expected namespace '%s', got '%s'", tt.expectedNamespace, metadata.Namespace)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseEdgeCases(t *testing.T) {
|
||||
parser := NewParser[MockParsable](nil)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
xmlData string
|
||||
expectError bool
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "XML with comments",
|
||||
xmlData: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- This is a comment -->
|
||||
<MockElement id="test-comments">
|
||||
<!-- Another comment -->
|
||||
<name>Test with comments</name>
|
||||
<value>Comments should be ignored</value>
|
||||
</MockElement>`,
|
||||
expectError: false,
|
||||
description: "XML with comments should parse successfully",
|
||||
},
|
||||
{
|
||||
name: "XML with CDATA",
|
||||
xmlData: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="test-cdata">
|
||||
<name>CDATA Test</name>
|
||||
<value><![CDATA[This is CDATA content with <special> characters]]></value>
|
||||
</MockElement>`,
|
||||
expectError: false,
|
||||
description: "XML with CDATA should parse successfully",
|
||||
},
|
||||
{
|
||||
name: "XML with special characters",
|
||||
xmlData: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MockElement id="test-special">
|
||||
<name>Special & Characters</name>
|
||||
<value><tag> "quoted" 'text'</value>
|
||||
</MockElement>`,
|
||||
expectError: false,
|
||||
description: "XML with escaped special characters should parse successfully",
|
||||
},
|
||||
{
|
||||
name: "Minimal valid XML",
|
||||
xmlData: `<MockElement id="minimal">
|
||||
<name>Minimal</name>
|
||||
<value>Test</value>
|
||||
</MockElement>`,
|
||||
expectError: false,
|
||||
description: "Minimal XML without declaration should parse successfully",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := parser.ParseString(tt.xmlData)
|
||||
|
||||
if tt.expectError {
|
||||
if err == nil {
|
||||
t.Errorf("%s: Expected error but got none", tt.description)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("%s: Unexpected error: %v", tt.description, err)
|
||||
return
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
t.Errorf("%s: Expected result to not be nil", tt.description)
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the result is valid
|
||||
if err := result.Validate(); err != nil {
|
||||
t.Errorf("%s: Result validation failed: %v", tt.description, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParserMemoryUsage(t *testing.T) {
|
||||
// Test parsing multiple documents to ensure no memory leaks
|
||||
parser := NewParser[MockParsable](nil)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
xmlData := strings.Replace(validMockXML, "test-123", fmt.Sprintf("test-%d", i), 1)
|
||||
result, err := parser.ParseString(xmlData)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Parse error on iteration %d: %v", i, err)
|
||||
break
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
t.Errorf("Nil result on iteration %d", i)
|
||||
break
|
||||
}
|
||||
|
||||
// Explicitly trigger validation to ensure full processing
|
||||
if err := result.Validate(); err != nil {
|
||||
t.Errorf("Validation error on iteration %d: %v", i, err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFromBuffer(t *testing.T) {
|
||||
// Test parsing from a bytes.Buffer
|
||||
buffer := bytes.NewBufferString(validMockXML)
|
||||
parser := NewParser[MockParsable](nil)
|
||||
|
||||
result, err := parser.Parse(buffer)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error parsing from buffer: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
t.Error("Expected result to not be nil")
|
||||
return
|
||||
}
|
||||
|
||||
if result.GetID() != "test-123" {
|
||||
t.Errorf("Expected ID 'test-123', got '%s'", result.GetID())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user