htree 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +4 -0
- data/Makefile +20 -0
- data/Manifest +58 -0
- data/README +61 -0
- data/Rakefile +37 -0
- data/htree.gemspec +32 -0
- data/init.rb +1 -0
- data/install.rb +112 -0
- data/lib/htree.rb +97 -0
- data/lib/htree/container.rb +8 -0
- data/lib/htree/context.rb +69 -0
- data/lib/htree/display.rb +46 -0
- data/lib/htree/doc.rb +149 -0
- data/lib/htree/elem.rb +262 -0
- data/lib/htree/encoder.rb +217 -0
- data/lib/htree/equality.rb +219 -0
- data/lib/htree/extract_text.rb +37 -0
- data/lib/htree/fstr.rb +32 -0
- data/lib/htree/gencode.rb +193 -0
- data/lib/htree/htmlinfo.rb +672 -0
- data/lib/htree/inspect.rb +108 -0
- data/lib/htree/leaf.rb +92 -0
- data/lib/htree/loc.rb +369 -0
- data/lib/htree/modules.rb +49 -0
- data/lib/htree/name.rb +122 -0
- data/lib/htree/output.rb +212 -0
- data/lib/htree/parse.rb +410 -0
- data/lib/htree/raw_string.rb +127 -0
- data/lib/htree/regexp-util.rb +19 -0
- data/lib/htree/rexml.rb +131 -0
- data/lib/htree/scan.rb +176 -0
- data/lib/htree/tag.rb +113 -0
- data/lib/htree/template.rb +961 -0
- data/lib/htree/text.rb +115 -0
- data/lib/htree/traverse.rb +497 -0
- data/test-all.rb +5 -0
- data/test/assign.html +1 -0
- data/test/template.html +4 -0
- data/test/test-attr.rb +67 -0
- data/test/test-charset.rb +79 -0
- data/test/test-context.rb +29 -0
- data/test/test-display_xml.rb +45 -0
- data/test/test-elem-new.rb +101 -0
- data/test/test-encoder.rb +53 -0
- data/test/test-equality.rb +55 -0
- data/test/test-extract_text.rb +18 -0
- data/test/test-gencode.rb +27 -0
- data/test/test-leaf.rb +25 -0
- data/test/test-loc.rb +60 -0
- data/test/test-namespace.rb +147 -0
- data/test/test-output.rb +133 -0
- data/test/test-parse.rb +115 -0
- data/test/test-raw_string.rb +17 -0
- data/test/test-rexml.rb +70 -0
- data/test/test-scan.rb +153 -0
- data/test/test-security.rb +37 -0
- data/test/test-subnode.rb +142 -0
- data/test/test-template.rb +313 -0
- data/test/test-text.rb +43 -0
- data/test/test-traverse.rb +69 -0
- metadata +166 -0
- metadata.gz.sig +1 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'htree'
|
3
|
+
|
4
|
+
class TestRawString < Test::Unit::TestCase
|
5
|
+
def test_elem
|
6
|
+
t = HTree.parse("<a>x</a>")
|
7
|
+
assert_equal("<a>x</a>", t.root.raw_string)
|
8
|
+
assert_equal("<a>x</a>", t.root.raw_string) # raw_string shouldn't have side effect.
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_no_raw_string
|
12
|
+
t = HTree::Elem.new('a')
|
13
|
+
assert_equal(nil, t.raw_string)
|
14
|
+
t = HTree::Elem.new('a', HTree.parse("<a>x</a>").root)
|
15
|
+
assert_equal(nil, t.raw_string)
|
16
|
+
end
|
17
|
+
end
|
data/test/test-rexml.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'htree/parse'
|
3
|
+
require 'htree/rexml'
|
4
|
+
begin
|
5
|
+
require 'rexml/document'
|
6
|
+
rescue LoadError
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestREXML < Test::Unit::TestCase
|
10
|
+
def test_doc
|
11
|
+
r = HTree.parse('<root/>').to_rexml
|
12
|
+
assert_instance_of(REXML::Document, r)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_elem
|
16
|
+
r = HTree.parse('<root a="b"/>').to_rexml
|
17
|
+
assert_instance_of(REXML::Element, e = r.root)
|
18
|
+
assert_equal('root', e.name)
|
19
|
+
assert_equal('b', e.attribute('a').to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_text
|
23
|
+
r = HTree.parse('<root>aaa</root>').to_rexml
|
24
|
+
assert_instance_of(REXML::Text, t = r.root.children[0])
|
25
|
+
assert_equal('aaa', t.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_xmldecl
|
29
|
+
s = '<?xml version="1.0"?>'
|
30
|
+
r = HTree.parse(s + '<root>aaa</root>').to_rexml
|
31
|
+
assert_instance_of(REXML::XMLDecl, x = r.children[0])
|
32
|
+
assert_equal('1.0', x.version)
|
33
|
+
assert_equal(nil, x.standalone)
|
34
|
+
|
35
|
+
assert_instance_of(REXML::XMLDecl, HTree.parse(s).children[0].to_rexml)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_doctype
|
39
|
+
s = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
|
40
|
+
r = HTree.parse(s + '<html><title>xxx</title></html>').to_rexml
|
41
|
+
assert_instance_of(REXML::DocType, d = r.children[0])
|
42
|
+
assert_equal('html', d.name)
|
43
|
+
assert_equal('PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"', d.external_id)
|
44
|
+
|
45
|
+
assert_instance_of(REXML::DocType, HTree.parse(s).children[0].to_rexml)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_procins
|
49
|
+
r = HTree.parse('<root><?xxx yyy?></root>').to_rexml
|
50
|
+
assert_instance_of(REXML::Instruction, i = r.root.children[0])
|
51
|
+
assert_equal('xxx', i.target)
|
52
|
+
assert_equal('yyy', i.content)
|
53
|
+
|
54
|
+
assert_instance_of(REXML::Instruction, HTree.parse('<?xxx yyy?>').children[0].to_rexml)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_comment
|
58
|
+
r = HTree.parse('<root><!-- zzz --></root>').to_rexml
|
59
|
+
assert_instance_of(REXML::Comment, c = r.root.children[0])
|
60
|
+
assert_equal(' zzz ', c.to_s)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_bogusetag
|
64
|
+
assert_equal(nil, HTree.parse('</e>').children[0].to_rexml)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_style
|
68
|
+
assert_equal('<style>a<b</style>', HTree.parse('<html><style>a<b</style></html>').to_rexml.to_s[/<style.*style>/])
|
69
|
+
end
|
70
|
+
end if defined? REXML
|
data/test/test-scan.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'htree/scan'
|
3
|
+
|
4
|
+
class TestScan < Test::Unit::TestCase
|
5
|
+
def scan(str)
|
6
|
+
result = []
|
7
|
+
HTree.scan(str) {|e| result << e }
|
8
|
+
result
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_empty
|
12
|
+
assert_equal([], scan(''))
|
13
|
+
end
|
14
|
+
|
15
|
+
def t_single(s)
|
16
|
+
n = yield
|
17
|
+
assert_equal([n], scan(s))
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_single
|
21
|
+
s = '<?xml version="1.0"?>'
|
22
|
+
assert_equal([[:xmldecl, s]], scan(s))
|
23
|
+
|
24
|
+
s = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
|
25
|
+
assert_equal([[:doctype, s]], scan(s))
|
26
|
+
|
27
|
+
s = '<?xxx yyy?>'
|
28
|
+
assert_equal([[:procins, s]], scan(s))
|
29
|
+
|
30
|
+
s = '<a>'
|
31
|
+
assert_equal([[:stag, s]], scan(s))
|
32
|
+
s = '</a>'
|
33
|
+
assert_equal([[:etag, s]], scan(s))
|
34
|
+
s = '<a/>'
|
35
|
+
assert_equal([[:emptytag, s]], scan(s))
|
36
|
+
s = '<!-- abc -->'
|
37
|
+
assert_equal([[:comment, s]], scan(s))
|
38
|
+
s = '<![CDATA[abc]]>'
|
39
|
+
assert_equal([[:text_cdata_section, s]], scan(s))
|
40
|
+
s = 'abc'
|
41
|
+
assert_equal([[:text_pcdata, s]], scan(s))
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_xmldecl_seen
|
45
|
+
s0 = '<?xml version="1.0"?>'
|
46
|
+
s1 = '<A>'
|
47
|
+
assert_equal([[:stag, s1]], scan(s1))
|
48
|
+
assert_equal([[:xmldecl, s0], [:stag, s1]], scan(s0 + s1))
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_cdata_content
|
52
|
+
s = '<html><script><a></script><a>'
|
53
|
+
assert_equal([
|
54
|
+
[:stag, '<html>'],
|
55
|
+
[:stag, '<script>'],
|
56
|
+
[:text_cdata_content, '<a>'],
|
57
|
+
[:etag, '</script>'],
|
58
|
+
[:stag, '<a>'],
|
59
|
+
], scan(s))
|
60
|
+
|
61
|
+
s = '<html><script><a>'
|
62
|
+
assert_equal([
|
63
|
+
[:stag, '<html>'],
|
64
|
+
[:stag, '<script>'],
|
65
|
+
[:text_cdata_content, '<a>'],
|
66
|
+
], scan(s))
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_text
|
70
|
+
s = 'a<e>b<e>c<e>d'
|
71
|
+
assert_equal([
|
72
|
+
[:text_pcdata, 'a'],
|
73
|
+
[:stag, '<e>'],
|
74
|
+
[:text_pcdata, 'b'],
|
75
|
+
[:stag, '<e>'],
|
76
|
+
[:text_pcdata, 'c'],
|
77
|
+
[:stag, '<e>'],
|
78
|
+
[:text_pcdata, 'd'],
|
79
|
+
], scan(s))
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_eol_html
|
83
|
+
# In SGML, a line break just after start tag and
|
84
|
+
# a line break just before end tag is ignored.
|
85
|
+
# http://www.w3.org/TR/REC-html40/appendix/notes.html#notes-line-breaks
|
86
|
+
#
|
87
|
+
# But usual browser including mozilla doesn't.
|
88
|
+
# So HTree doesn't ignore them and treat as usual text.
|
89
|
+
s = "<html>a\n<e>\nb\n<f>\nc\n</f>\nd\n</e>\ne"
|
90
|
+
assert_equal([
|
91
|
+
[:stag, "<html>"],
|
92
|
+
[:text_pcdata, "a\n"],
|
93
|
+
[:stag, "<e>"],
|
94
|
+
[:text_pcdata, "\nb\n"],
|
95
|
+
[:stag, "<f>"],
|
96
|
+
[:text_pcdata, "\nc\n"],
|
97
|
+
[:etag, "</f>"],
|
98
|
+
[:text_pcdata, "\nd\n"],
|
99
|
+
[:etag, "</e>"],
|
100
|
+
[:text_pcdata, "\ne"],
|
101
|
+
], scan(s))
|
102
|
+
|
103
|
+
s = "<html>a\n<e>\nb\n<script>\nc\n</script>\nd\n</e>\ne"
|
104
|
+
assert_equal([
|
105
|
+
[:stag, "<html>"],
|
106
|
+
[:text_pcdata, "a\n"],
|
107
|
+
[:stag, "<e>"],
|
108
|
+
[:text_pcdata, "\nb\n"],
|
109
|
+
[:stag, "<script>"],
|
110
|
+
[:text_cdata_content, "\nc\n"],
|
111
|
+
[:etag, "</script>"],
|
112
|
+
[:text_pcdata, "\nd\n"],
|
113
|
+
[:etag, "</e>"],
|
114
|
+
[:text_pcdata, "\ne"],
|
115
|
+
], scan(s))
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_eol_xml
|
120
|
+
# In XML, line breaks are treated as part of content.
|
121
|
+
# It's because KEEPRSRE is yes in XML.
|
122
|
+
# http://www.satoshii.org/markup/websgml/valid-xml#keeprsre
|
123
|
+
s = "<?xml version='1.0'?>a\n<e>\nb\n<f>\nc\n</f>\nd\n</e>\ne"
|
124
|
+
assert_equal([
|
125
|
+
[:xmldecl, "<?xml version='1.0'?>"],
|
126
|
+
[:text_pcdata, "a\n"],
|
127
|
+
[:stag, "<e>"],
|
128
|
+
[:text_pcdata, "\nb\n"],
|
129
|
+
[:stag, "<f>"],
|
130
|
+
[:text_pcdata, "\nc\n"],
|
131
|
+
[:etag, "</f>"],
|
132
|
+
[:text_pcdata, "\nd\n"],
|
133
|
+
[:etag, "</e>"],
|
134
|
+
[:text_pcdata, "\ne"],
|
135
|
+
], scan(s))
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_xml_html_detection
|
139
|
+
assert_equal([false, true], HTree.scan("<html></html>") {})
|
140
|
+
assert_equal([true, false], HTree.scan("<rss></rss>") {})
|
141
|
+
assert_equal([true, true], HTree.scan('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') {})
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_quoted_attr
|
145
|
+
assert_equal([[:emptytag, '<e a=">"/>']], scan('<e a=">"/>'))
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_bare_slash
|
149
|
+
assert_equal([[:stag, '<n dir=/foo/bar/>']], scan('<n dir=/foo/bar/>'))
|
150
|
+
assert_equal([[:stag, '<n a=v/>']], scan('<n a=v/>'))
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'htree/parse'
|
3
|
+
require 'htree/template'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
class TestSecurity < Test::Unit::TestCase
|
7
|
+
def safe(n)
|
8
|
+
assert_equal(0, $SAFE)
|
9
|
+
Thread.new {
|
10
|
+
$SAFE = n
|
11
|
+
assert_equal(n, $SAFE)
|
12
|
+
yield
|
13
|
+
}.join
|
14
|
+
assert_equal(0, $SAFE)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_parse
|
18
|
+
safe(1) {
|
19
|
+
assert_equal(1, $SAFE)
|
20
|
+
assert_nothing_raised { HTree.parse("") }
|
21
|
+
assert_raise(SecurityError) { HTree.parse("".taint) }
|
22
|
+
}
|
23
|
+
assert_nothing_raised { HTree.parse("") }
|
24
|
+
assert_nothing_raised { HTree.parse("".taint) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_template
|
28
|
+
safe(1) {
|
29
|
+
assert_nothing_raised { HTree.expand_template("/dev/null", nil, '') }
|
30
|
+
assert_raise(SecurityError) { HTree.expand_template("/dev/null".taint, nil, '') }
|
31
|
+
}
|
32
|
+
assert_nothing_raised { HTree.expand_template("/dev/null", nil, '') }
|
33
|
+
assert_nothing_raised { HTree.expand_template("/dev/null".taint, nil, '') }
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'htree'
|
3
|
+
|
4
|
+
class TestSubnode < Test::Unit::TestCase
|
5
|
+
def test_elem_get
|
6
|
+
e1 = HTree.parse("<a href=x>abc</a>").root
|
7
|
+
assert_equal(HTree::Text.new("x"), e1.get_subnode("href"))
|
8
|
+
assert_equal(HTree::Text.new("abc"), e1.get_subnode(0))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_elem_subst
|
12
|
+
e1 = HTree.parse_xml("<a href=x>abc</a>").root
|
13
|
+
e2 = e1.subst_subnode("href"=>"xxx", 0=>"def")
|
14
|
+
assert_equal("a", e2.name)
|
15
|
+
assert_equal("xxx", e2.fetch_attr("href"))
|
16
|
+
assert_equal([HTree::Text.new("def")], e2.children)
|
17
|
+
assert_equal([], e1.subst_subnode(0=>nil).children)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_elem_subst_empty
|
21
|
+
e1 = HTree.parse("<img />").root
|
22
|
+
assert_equal(true, e1.empty_element?)
|
23
|
+
assert_equal(true, e1.subst_subnode("src"=>"xxx").empty_element?)
|
24
|
+
assert_equal(false, e1.subst_subnode(0=>"xxx").empty_element?)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_elem_multiple_attr_value
|
28
|
+
h = {"b"=>"c", HTree::Name.new(nil, "", "b")=>"d"}
|
29
|
+
assert_match(/\A(cd|dc)\z/,
|
30
|
+
HTree::Elem.new("a").subst_subnode(h).get_subnode('b').to_s)
|
31
|
+
|
32
|
+
a = [["b","c"], [HTree::Name.new(nil, "", "b"),"d"]]
|
33
|
+
assert_equal('cd',
|
34
|
+
HTree::Elem.new("a").subst_subnode(a).get_subnode('b').to_s)
|
35
|
+
assert_equal('dc',
|
36
|
+
HTree::Elem.new("a").subst_subnode(a.reverse).get_subnode('b').to_s)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_elem_subst_outrange
|
40
|
+
e1 = HTree("<r>abc</r>").root
|
41
|
+
e2 = e1.subst_subnode(-1=>HTree('<x/>'), 1=>HTree('<y/>'))
|
42
|
+
assert_equal(HTree('<r><x/>abc<y/></r>').root, e2)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_doc_subst_outrange
|
46
|
+
d1 = HTree("<r>abc</r>")
|
47
|
+
d2 = d1.subst_subnode(-1=>HTree('<x/>'), 1=>HTree('<y/>'))
|
48
|
+
assert_equal(HTree('<x/><r>abc</r><y/>'), d2)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_doc_get
|
52
|
+
doc = HTree.parse("<?xml?><a href=x>abc</a> ")
|
53
|
+
assert_equal(doc.root, doc.get_subnode(1))
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_doc_subst
|
57
|
+
doc1 = HTree.parse("<?xml?><a href=x>abc</a> ")
|
58
|
+
doc2 = doc1.subst_subnode(1=>"yy")
|
59
|
+
assert_equal(HTree::Text.new("yy"), doc2.children[1])
|
60
|
+
assert_equal([], doc1.subst_subnode(0=>nil, 1=>nil, 2=>nil).children)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_doc_loc
|
64
|
+
d1 = HTree.parse("<r>a</r>")
|
65
|
+
d2 = HTree.parse("<q/>")
|
66
|
+
assert_equal(d2, d1.subst_subnode(0=>d2.make_loc))
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_doc
|
70
|
+
e = HTree.parse("<r>a</r>").root
|
71
|
+
d = HTree.parse("<?xml version='1.0'?><!DOCTYPE q><q/>")
|
72
|
+
r = HTree('<r><q/></r>').root
|
73
|
+
assert_equal(r, e.subst_subnode(0=>d))
|
74
|
+
assert_equal(r, e.subst_subnode(0=>d.make_loc))
|
75
|
+
assert_equal(r, e.subst_subnode(0=>[d]))
|
76
|
+
assert_equal(r, e.subst_subnode(0=>[d.make_loc]))
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_doc2
|
80
|
+
e = HTree.parse("<r>a</r>")
|
81
|
+
d = HTree.parse("<?xml version='1.0'?><!DOCTYPE q><q/>")
|
82
|
+
r = HTree('<q/>')
|
83
|
+
assert_equal(r, e.subst_subnode(0=>d))
|
84
|
+
assert_equal(r, e.subst_subnode(0=>d.make_loc))
|
85
|
+
assert_equal(r, e.subst_subnode(0=>[d]))
|
86
|
+
assert_equal(r, e.subst_subnode(0=>[d.make_loc]))
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_change_by_subst_itself
|
90
|
+
l = HTree("<r>a</r>").make_loc
|
91
|
+
l2 = l.get_subnode(0, 0).subst_itself('x')
|
92
|
+
assert_equal(HTree::Text.new('x'), l2.to_node)
|
93
|
+
assert_equal(HTree('<r>x</r>'), l2.top.to_node)
|
94
|
+
l2 = l.get_subnode(0).subst_itself('xxx')
|
95
|
+
assert_equal(HTree::Text.new('xxx'), l2.to_node)
|
96
|
+
assert_equal(HTree('xxx'), l2.top.to_node)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_add_by_subst_itself
|
100
|
+
l = HTree("<r>a</r>").make_loc
|
101
|
+
l2 = l.get_subnode(0, 'x').subst_itself('y')
|
102
|
+
assert_equal(HTree::Text.new('y'), l2.to_node)
|
103
|
+
assert_equal(HTree('<r x="y">a</r>'), l2.top.to_node)
|
104
|
+
l2 = l.get_subnode(0, 0).subst_itself('b')
|
105
|
+
assert_equal(HTree::Text.new('b'), l2.to_node)
|
106
|
+
assert_equal(HTree('<r>b</r>'), l2.top.to_node)
|
107
|
+
xmldecl = HTree('<?xml version="1.0"?>').get_subnode(0)
|
108
|
+
l2 = l.get_subnode(-1).subst_itself(xmldecl)
|
109
|
+
assert_equal(0, l2.index)
|
110
|
+
assert_equal(xmldecl, l2.to_node)
|
111
|
+
assert_equal(HTree('<?xml version="1.0"?><r>a</r>'), l2.top.to_node)
|
112
|
+
procins = HTree('<?xxx yyy?>').get_subnode(0)
|
113
|
+
l2 = l.get_subnode(10).subst_itself(procins)
|
114
|
+
assert_equal(1, l2.index)
|
115
|
+
assert_equal(procins, l2.to_node)
|
116
|
+
assert_equal(HTree('<r>a</r><?xxx yyy?>'), l2.top.to_node)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_del_by_subst_itself
|
120
|
+
l = HTree("<r x='y'><x/>y<z/></r>").make_loc
|
121
|
+
l2 = l.get_subnode(0, 'x').subst_itself(nil)
|
122
|
+
assert_equal(nil, l2.to_node)
|
123
|
+
assert_equal(HTree('<r><x/>y<z/></r>'), l2.top.to_node)
|
124
|
+
l2 = l.get_subnode(0, 1).subst_itself(nil)
|
125
|
+
assert_equal(HTree('<r x="y"><x/><z/></r>'), l2.top.to_node)
|
126
|
+
l = HTree('<?xml version="1.0"?><r/>').make_loc
|
127
|
+
l2 = l.get_subnode(0).subst_itself(nil)
|
128
|
+
assert_equal(HTree('<r/>'), l2.top.to_node)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_subst
|
132
|
+
l = HTree('<?xml version="1.0"?><r><x/><y/><z/></r>').make_loc
|
133
|
+
assert_equal(HTree("<r>x<y>a</y><z k=v /></r>"),
|
134
|
+
l.to_node.subst({
|
135
|
+
l.get_subnode(0) => nil,
|
136
|
+
l.get_subnode(1, 0) => 'x',
|
137
|
+
l.get_subnode(1, 1, 0) => 'a',
|
138
|
+
l.get_subnode(1, 2, 'k') => 'v'
|
139
|
+
}))
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'htree/template'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
class TestTemplate < Test::Unit::TestCase
|
6
|
+
Decl = '<?xml version="1.0" encoding="US-ASCII"?>'
|
7
|
+
|
8
|
+
def assert_xhtml(expected, template, message=nil)
|
9
|
+
prefix = '<?xml version="1.0" encoding="US-ASCII"?>' +
|
10
|
+
"<html xmlns=\"http://www.w3.org/1999/xhtml\"\n>"
|
11
|
+
suffix = "</html\n>"
|
12
|
+
result = HTree.expand_template(''){"<?xml version=\"1.0\"?><html>#{template}</html>"}
|
13
|
+
assert_match(/\A#{Regexp.quote prefix}/, result)
|
14
|
+
assert_match(/#{Regexp.quote suffix}\z/, result)
|
15
|
+
result = result[prefix.length..(-suffix.length-1)]
|
16
|
+
assert_equal(expected, result, message)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_text
|
20
|
+
assert_xhtml("<e\n>1</e\n>", '<e _text=1>d</e>')
|
21
|
+
assert_xhtml('1', '<span _text=1>d</span>')
|
22
|
+
assert_xhtml("<span x=\"2\"\n>1</span\n>", '<span x=2 _text=1>d</span>')
|
23
|
+
assert_xhtml("abc", %q{a<span _text="'b'"/>c})
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_tree
|
27
|
+
assert_xhtml("<e\n><z\n>x</z\n></e\n>", '<e _tree="HTree("<z>x</z>")">d</e>')
|
28
|
+
assert_xhtml("<n:e xmlns:n=\"a\"\n><n:z\n>x</n:z\n></n:e\n>", '<n:e xmlns:n=a _tree="HTree("<n:z xmlns:n=a>x</n:z>")">d</n:e>')
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_attr
|
32
|
+
assert_xhtml("<e x=\"1\"\n>d</e\n>", '<e _attr_x=1>d</e>')
|
33
|
+
assert_xhtml("<span x=\"1\"\n>d</span\n>", '<span _attr_x=1>d</span>')
|
34
|
+
assert_xhtml("<span x=\""\"\n>d</span\n>", '<span _attr_x=\'"\x22"\'>d</span>')
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_if
|
38
|
+
assert_xhtml("<e\n>d</e\n>", '<e _if=true>d</e>')
|
39
|
+
assert_xhtml('', '<e _if=false>d</e>')
|
40
|
+
assert_xhtml("<f\n>dd</f\n>", '<e _if=false _else=m>d</e><f _template=m>dd</f>')
|
41
|
+
|
42
|
+
assert_xhtml('d', '<span _if=true>d</span>')
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_iter
|
46
|
+
assert_xhtml("<o\n><i\n>1</i\n></o\n><o\n><i\n>2</i\n></o\n><o\n><i\n>3</i\n></o\n>",
|
47
|
+
'<o _iter=[1,2,3].each//v><i _text=v /></o>')
|
48
|
+
assert_xhtml("<i\n>1</i\n><i\n>2</i\n><i\n>3</i\n>",
|
49
|
+
'<span _iter=[1,2,3].each//v><i _text=v /></span>')
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_iter_content
|
53
|
+
assert_xhtml("<o\n><i\n>1</i\n><i\n>2</i\n><i\n>3</i\n></o\n>",
|
54
|
+
'<o _iter_content=[1,2,3].each//v><i _text=v /></o>')
|
55
|
+
assert_xhtml("<i\n>1</i\n><i\n>2</i\n><i\n>3</i\n>",
|
56
|
+
'<span _iter_content=[1,2,3].each//v><i _text=v /></span>')
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_iter_local_template
|
60
|
+
assert_xhtml("<o\n><i\n>1</i\n></o\n><o\n><i\n>2</i\n></o\n><o\n><i\n>3</i\n></o\n>",
|
61
|
+
'<o _iter=[1,2,3].each//v><i _call=m /><i _template=m _text=v></i></o>')
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_call
|
65
|
+
assert_xhtml("<f\n>1</f\n>",
|
66
|
+
'<e _call=m(1) /><f _template=m(v) _text=v></f>')
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_template
|
70
|
+
assert_xhtml('d',
|
71
|
+
'<span _template="span()">d</span><e _call="span()"></e>')
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_file
|
75
|
+
assert_equal(<<'End'.chop,
|
76
|
+
<?xml version="1.0" encoding="US-ASCII"?><html xmlns="http://www.w3.org/1999/xhtml"
|
77
|
+
><title
|
78
|
+
>aaa</title
|
79
|
+
></html
|
80
|
+
>
|
81
|
+
End
|
82
|
+
HTree.expand_template("#{File.dirname __FILE__}/template.html", "aaa", ''))
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_whitespace
|
86
|
+
assert_xhtml("<x\n></x\n>", '<x> </x>')
|
87
|
+
assert_xhtml("<x\n> </x\n>", '<x> </x>')
|
88
|
+
assert_xhtml("<pre\n> </pre\n>", '<pre> </pre>')
|
89
|
+
assert_xhtml(" ", %q{<span _text="' '"> </span>})
|
90
|
+
assert_xhtml(" ", %q{<span _text="' '"/>})
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_ignorable
|
94
|
+
assert_xhtml("<div\n>a</div\n>", '<div>a</div>')
|
95
|
+
assert_xhtml("<span\n>a</span\n>", '<span>a</span>')
|
96
|
+
assert_xhtml("1", '<span _text="1">a</span>')
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_not_ignorable
|
100
|
+
assert_xhtml("<p\n>1</p\n>", '<p _text="\'1\'">a</p>')
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_template_in_attr
|
104
|
+
assert_xhtml("<a x=\"1\"\n></a\n>", '<a _attr_x=1><b _template=m></b></a>')
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_empty_block_argument
|
108
|
+
assert_xhtml("vv", '<span _iter="2.times//">v</span>')
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_empty_element
|
112
|
+
assert_xhtml("<elem\n/>", '<elem />') # 2004-06-10: reported by Takuo KITAME
|
113
|
+
assert_xhtml("<elem x=\"1\"\n/>", '<elem _attr_x=1 />')
|
114
|
+
assert_xhtml("<elem\n></elem\n>", '<elem _text=\'""\' />')
|
115
|
+
assert_xhtml("<elem\n/>", '<elem _if="true" />')
|
116
|
+
assert_xhtml("", '<elem _if="false" />')
|
117
|
+
assert_xhtml("<foo\n/>", '<elem _if="false" _else="foo"/><foo _template="foo"/>')
|
118
|
+
assert_xhtml("<elem\n/><elem\n/>", '<elem _iter="2.times//" />')
|
119
|
+
assert_xhtml("<elem\n></elem\n>", '<elem _iter_content="2.times//" />')
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_empty_element_start_end_tag
|
123
|
+
assert_xhtml("<elem\n></elem\n>", '<elem></elem>')
|
124
|
+
assert_xhtml("<elem x=\"1\"\n></elem\n>", '<elem _attr_x=1 ></elem>')
|
125
|
+
assert_xhtml("<elem\n></elem\n>", '<elem _text=\'""\' ></elem>')
|
126
|
+
assert_xhtml("<elem\n></elem\n>", '<elem _if="true" ></elem>')
|
127
|
+
assert_xhtml("", '<elem _if="false" ></elem>')
|
128
|
+
assert_xhtml("<foo\n></foo\n>", '<elem _if="false" _else="foo"></elem><foo _template="foo"></foo>')
|
129
|
+
assert_xhtml("<elem\n></elem\n><elem\n></elem\n>", '<elem _iter="2.times//" ></elem>')
|
130
|
+
assert_xhtml("<elem\n></elem\n>", '<elem _iter_content="2.times//" ></elem>')
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_toplevel_local_variable
|
134
|
+
eval("htree_test_toplevel_local_variable = :non_modified_value", TOPLEVEL_BINDING)
|
135
|
+
HTree.expand_template("#{File.dirname __FILE__}/assign.html", "aaa", '')
|
136
|
+
assert_equal(:non_modified_value, eval("htree_test_toplevel_local_variable", TOPLEVEL_BINDING))
|
137
|
+
eval("htree_test_toplevel_local_variable = 1", TOPLEVEL_BINDING)
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_extend_compiled_template
|
141
|
+
m = HTree.compile_template('<div _template="m">self is <span _text="inspect"></span></div>')
|
142
|
+
o = "zzz"
|
143
|
+
o.extend m
|
144
|
+
assert_equal('<?xml version="1.0" encoding="US-ASCII"?>self is "zzz"',
|
145
|
+
HTree.expand_template(''){'<div _call="o.m"></div>'})
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_attr_nbsp
|
149
|
+
@t = HTree::Text.parse_pcdata(' ')
|
150
|
+
assert_xhtml("<span x=\" \"\n>d</span\n>", '<span _attr_x="@t">d</span>')
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_text_nbsp
|
154
|
+
@t = HTree::Text.parse_pcdata(' ')
|
155
|
+
assert_xhtml(" ", '<span _text="@t">d</span>')
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_content_text
|
159
|
+
assert_xhtml("<e\n>ab</e\n>", '<e _text>"a"+"b"</e>')
|
160
|
+
assert_xhtml("<e\n>2</e\n>", '<e _text>1+1</e>')
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
class MemFile
|
166
|
+
def initialize(str)
|
167
|
+
@str = str
|
168
|
+
end
|
169
|
+
|
170
|
+
def read
|
171
|
+
@str
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class TestTemplateScopeObj
|
176
|
+
Const = 'good_const'
|
177
|
+
@@cvar = 'good_cvar'
|
178
|
+
def initialize
|
179
|
+
@ivar = 'good_ivar'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class TestTemplateScope < Test::Unit::TestCase
|
184
|
+
Const = 'bad_const'
|
185
|
+
@@cvar = 'bad_cvar'
|
186
|
+
def setup
|
187
|
+
@ivar = 'bad_ivar'
|
188
|
+
eval("test_local_variable = 'bad_lvar'", TOPLEVEL_BINDING)
|
189
|
+
end
|
190
|
+
|
191
|
+
XMLDeclStr = '<?xml version="1.0" encoding="US-ASCII"?>'
|
192
|
+
|
193
|
+
def test_expand_template
|
194
|
+
obj = TestTemplateScopeObj.new
|
195
|
+
assert_equal("#{XMLDeclStr}[TestTemplateScopeObj]",
|
196
|
+
HTree.expand_template(MemFile.new('<span _text="Module.nesting.inspect"/>'), obj, ''))
|
197
|
+
assert_equal("#{XMLDeclStr}good_ivar",
|
198
|
+
HTree.expand_template(MemFile.new('<span _text="@ivar"/>'), obj, ''))
|
199
|
+
assert_equal("#{XMLDeclStr}good_cvar",
|
200
|
+
HTree.expand_template(MemFile.new('<span _text="@@cvar"/>'), obj, ''))
|
201
|
+
assert_equal("#{XMLDeclStr}good_const",
|
202
|
+
HTree.expand_template(MemFile.new('<span _text="Const"/>'), obj, ''))
|
203
|
+
test_local_variable = 'bad_lvar'
|
204
|
+
assert_equal("#{XMLDeclStr}good_lvar",
|
205
|
+
HTree.expand_template(MemFile.new('<span _text="begin test_local_variable rescue NameError; \'good_lvar\' end"/>'), obj, ''))
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_compile_template
|
209
|
+
obj = TestTemplateScopeObj.new
|
210
|
+
mod = HTree.compile_template(MemFile.new(<<-'End'))
|
211
|
+
<span _template=test_nesting _text="Module.nesting.inspect"/>
|
212
|
+
<span _template=test_const _text="Const"/>
|
213
|
+
<span _template=test_cvar _text="@@cvar"/>
|
214
|
+
<span _template=test_ivar _text="@ivar"/>
|
215
|
+
End
|
216
|
+
mod.module_eval <<-'End'
|
217
|
+
Const = 'mod_const'
|
218
|
+
@@cvar = 'mod_cvar'
|
219
|
+
@ivar = 'mod_ivar'
|
220
|
+
End
|
221
|
+
assert_equal("[#{mod.inspect}]", mod.test_nesting.extract_text.to_s)
|
222
|
+
assert_equal("mod_const", mod.test_const.extract_text.to_s)
|
223
|
+
assert_equal("mod_cvar", mod.test_cvar.extract_text.to_s)
|
224
|
+
assert_equal("mod_ivar", mod.test_ivar.extract_text.to_s)
|
225
|
+
obj = Object.new
|
226
|
+
obj.instance_variable_set :@ivar, 'obj_ivar'
|
227
|
+
obj.extend mod
|
228
|
+
assert_equal("[#{mod.inspect}]", obj.__send__(:test_nesting).extract_text.to_s)
|
229
|
+
assert_equal("mod_const", obj.__send__(:test_const).extract_text.to_s)
|
230
|
+
assert_equal("mod_cvar", obj.__send__(:test_cvar).extract_text.to_s)
|
231
|
+
assert_equal("obj_ivar", obj.__send__(:test_ivar).extract_text.to_s)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
class TestCDATA < Test::Unit::TestCase
|
236
|
+
def test_html_script
|
237
|
+
v = "x<y"
|
238
|
+
assert_equal("<html><script>x<y</script></html>",
|
239
|
+
HTree.expand_template('') {"<html><script _text=\"v\">ab</script>"}.gsub(/\n/, ''))
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_xml_script
|
243
|
+
v = "x<y"
|
244
|
+
assert_equal("<?xml version=\"1.0\" encoding=\"US-ASCII\"?><html xmlns=\"http://www.w3.org/1999/xhtml\"><script>x<y</script></html>",
|
245
|
+
HTree.expand_template('') {"<?xml version=\"1.0\"?><html><script _text=\"v\">ab</script>"}.gsub(/\n/, ''))
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_html_script_invalid_content
|
249
|
+
v = "x</y"
|
250
|
+
assert_raise(ArgumentError) {
|
251
|
+
HTree.expand_template('') {"<html><script _text=\"v\">ab</script>"}
|
252
|
+
}
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_stylexxx
|
256
|
+
v = "x<y"
|
257
|
+
assert_equal("<html><stylexxx>x<y</stylexxx></html>",
|
258
|
+
HTree.expand_template('') {"<html><stylexxx _text=\"v\">ab</stylexxx>"}.gsub(/\n/, ''))
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
class TestCharset2 < Test::Unit::TestCase
|
264
|
+
class CharsetString < String
|
265
|
+
attr_accessor :charset
|
266
|
+
end
|
267
|
+
|
268
|
+
def with_kcode(kcode)
|
269
|
+
if "".respond_to? :force_encoding
|
270
|
+
if HTree::Encoder.internal_charset.start_with?(kcode.upcase)
|
271
|
+
yield
|
272
|
+
end
|
273
|
+
else
|
274
|
+
old = $KCODE
|
275
|
+
begin
|
276
|
+
$KCODE = kcode
|
277
|
+
yield
|
278
|
+
ensure
|
279
|
+
$KCODE = old
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_us_ascii
|
285
|
+
with_kcode('E') {
|
286
|
+
out = HTree.expand_template(CharsetString.new) { "<html>abc" }
|
287
|
+
assert_equal(out.charset, 'US-ASCII')
|
288
|
+
}
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_euc_jp
|
292
|
+
with_kcode('E') {
|
293
|
+
out = HTree.expand_template(CharsetString.new) { "<html>\xa1\xa1" }
|
294
|
+
assert_equal(out.charset, 'EUC-JP')
|
295
|
+
}
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_utf_8
|
299
|
+
with_kcode('U') {
|
300
|
+
out = HTree.expand_template(CharsetString.new) { "<html>\xc2\xa1" }
|
301
|
+
assert_equal(out.charset, 'UTF-8')
|
302
|
+
}
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
306
|
+
|
307
|
+
class TestTemplateDOCTYPE < Test::Unit::TestCase
|
308
|
+
def test_html
|
309
|
+
assert_equal(
|
310
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html></html>',
|
311
|
+
HTree.expand_template('') {'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>'}.gsub(/\n/, ''))
|
312
|
+
end
|
313
|
+
end
|