-
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdocument_test.go
More file actions
145 lines (121 loc) · 4.13 KB
/
Copy pathdocument_test.go
File metadata and controls
145 lines (121 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package helium_test
import (
"testing"
"github.com/lestrrat-go/helium"
"github.com/lestrrat-go/helium/internal/lexicon"
"github.com/stretchr/testify/require"
)
func TestGetElementByID(t *testing.T) {
t.Run("xml:id via parser", func(t *testing.T) {
t.Parallel()
const input = `<?xml version="1.0"?>
<root>
<a xml:id="first">one</a>
<b xml:id="second">two</b>
</root>`
p := helium.NewParser()
doc, err := p.Parse(t.Context(), []byte(input))
require.NoError(t, err)
// O(1) lookup via ID table
elem := doc.GetElementByID("first")
require.NotNil(t, elem)
require.Equal(t, "a", elem.LocalName())
elem = doc.GetElementByID("second")
require.NotNil(t, elem)
require.Equal(t, "b", elem.LocalName())
// Non-existent ID
elem = doc.GetElementByID("missing")
require.Nil(t, elem)
})
t.Run("DTD-declared ID via parser", func(t *testing.T) {
t.Parallel()
const input = `<?xml version="1.0"?>
<!DOCTYPE root [
<!ELEMENT root (item*)>
<!ELEMENT item (#PCDATA)>
<!ATTLIST item eid ID #IMPLIED>
]>
<root>
<item eid="x1">alpha</item>
<item eid="x2">beta</item>
</root>`
p := helium.NewParser().LoadExternalDTD(true).DefaultDTDAttributes(true)
doc, err := p.Parse(t.Context(), []byte(input))
require.NoError(t, err)
elem := doc.GetElementByID("x1")
require.NotNil(t, elem)
require.Equal(t, "item", elem.LocalName())
elem = doc.GetElementByID("x2")
require.NotNil(t, elem)
require.Equal(t, "item", elem.LocalName())
})
t.Run("fallback tree walk for programmatic documents", func(t *testing.T) {
t.Parallel()
// Documents built without parsing have no ID table,
// so GetElementByID falls back to O(n) tree walk.
doc := helium.NewDefaultDocument()
root := doc.CreateElement("root")
require.NoError(t, doc.AddChild(root))
child := doc.CreateElement("child")
ns := helium.NewNamespace("xml", lexicon.NamespaceXML)
_, err := child.SetAttributeNS("id", "myid", ns)
require.NoError(t, err)
require.NoError(t, root.AddChild(child))
elem := doc.GetElementByID("myid")
require.NotNil(t, elem)
require.Equal(t, "child", elem.LocalName())
elem = doc.GetElementByID("missing")
require.Nil(t, elem)
})
t.Run("ID table populated on parse", func(t *testing.T) {
t.Parallel()
const input = `<?xml version="1.0"?>
<root xml:id="r">
<child xml:id="c"/>
</root>`
p := helium.NewParser()
doc, err := p.Parse(t.Context(), []byte(input))
require.NoError(t, err)
require.NotNil(t, doc.GetElementByID("r"))
require.NotNil(t, doc.GetElementByID("c"))
})
t.Run("after parse", func(t *testing.T) {
t.Parallel()
const input = `<root xml:id="root-id"><child xml:id="child-id"/></root>`
doc, err := helium.NewParser().Parse(t.Context(), []byte(input))
require.NoError(t, err)
require.NotNil(t, doc.GetElementByID("root-id"))
require.NotNil(t, doc.GetElementByID("child-id"))
})
t.Run("after parse with SkipIDs", func(t *testing.T) {
t.Parallel()
const input = `<root xml:id="root-id"><child xml:id="child-id"/></root>`
doc, err := helium.NewParser().SkipIDs(true).Parse(t.Context(), []byte(input))
require.NoError(t, err)
require.Nil(t, doc.GetElementByID("root-id"))
require.Nil(t, doc.GetElementByID("child-id"))
})
}
func TestDocProperties(t *testing.T) {
t.Parallel()
t.Run("new default document is user-built", func(t *testing.T) {
t.Parallel()
doc := helium.NewDefaultDocument()
require.True(t, doc.HasProperty(helium.DocUserBuilt))
})
t.Run("HasProperty requires all requested bits", func(t *testing.T) {
t.Parallel()
doc := helium.NewDocument("1.0", "", helium.StandaloneImplicitNo)
doc.SetProperties(helium.DocWellFormed | helium.DocXInclude)
require.True(t, doc.HasProperty(helium.DocWellFormed))
require.True(t, doc.HasProperty(helium.DocXInclude))
require.True(t, doc.HasProperty(helium.DocWellFormed|helium.DocXInclude))
require.False(t, doc.HasProperty(helium.DocWellFormed|helium.DocDTDValid))
})
}
func TestCreatePIOwnerDocument(t *testing.T) {
t.Parallel()
doc := helium.NewDocument("1.0", "", helium.StandaloneImplicitNo)
pi := doc.CreatePI("p", "data")
require.Same(t, doc, pi.OwnerDocument(), "PI owner document should be the creating document")
}