builder 3.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,611 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Portions copyright 2004 by Jim Weirich (jim@weirichhouse.org).
5
+ # Portions copyright 2005 by Sam Ruby (rubys@intertwingly.net).
6
+ # All rights reserved.
7
+
8
+ # Permission is granted for use, copying, modification, distribution,
9
+ # and distribution of modified versions of this work as long as the
10
+ # above copyright notice is included.
11
+ #++
12
+
13
+ require 'helper'
14
+ require 'preload'
15
+ require 'builder'
16
+ require 'builder/xmlmarkup'
17
+
18
+ class TestMarkup < Builder::Test
19
+ def setup
20
+ @xml = Builder::XmlMarkup.new
21
+ end
22
+
23
+ def test_create
24
+ assert_not_nil @xml
25
+ end
26
+
27
+ def test_simple
28
+ @xml.simple
29
+ assert_equal "<simple/>", @xml.target!
30
+ end
31
+
32
+ def test_value
33
+ @xml.value("hi")
34
+ assert_equal "<value>hi</value>", @xml.target!
35
+ end
36
+
37
+ def test_empty_value
38
+ @xml.value("")
39
+ assert_equal "<value></value>", @xml.target!
40
+ end
41
+
42
+ def test_nil_value
43
+ @xml.value(nil)
44
+ assert_equal "<value/>", @xml.target!
45
+ end
46
+
47
+ def test_no_value
48
+ @xml.value()
49
+ assert_equal "<value/>", @xml.target!
50
+ end
51
+
52
+ def test_nested
53
+ @xml.outer { |x| x.inner("x") }
54
+ assert_equal "<outer><inner>x</inner></outer>", @xml.target!
55
+ end
56
+
57
+ def test_attributes
58
+ @xml.ref(:id => 12)
59
+ assert_equal %{<ref id="12"/>}, @xml.target!
60
+ end
61
+
62
+ def test_single_quotes_for_attrs
63
+ @xml = Builder::XmlMarkup.new(:quote => :single)
64
+ @xml.ref(:id => 12)
65
+ assert_equal %{<ref id='12'/>}, @xml.target!
66
+ end
67
+
68
+ def test_mixed_quotes_for_attrs
69
+ @xml = Builder::XmlMarkup.new(:quote => :single)
70
+ x = Builder::XmlMarkup.new(:target=>@xml, :quote => :double)
71
+ @xml.ref(:id => 12) do
72
+ x.link(:id => 13)
73
+ end
74
+ assert_equal %{<ref id='12'><link id="13"/></ref>}, @xml.target!
75
+ end
76
+
77
+ def test_string_attributes_are_escaped_by_default
78
+ @xml.ref(:id => "H&R")
79
+ assert_equal %{<ref id="H&amp;R"/>}, @xml.target!
80
+ end
81
+
82
+ def test_symbol_attributes_are_unescaped_by_default
83
+ @xml.ref(:id => :"H&amp;R")
84
+ assert_equal %{<ref id="H&amp;R"/>}, @xml.target!
85
+ end
86
+
87
+ def test_attributes_escaping_can_be_turned_on
88
+ @xml = Builder::XmlMarkup.new
89
+ @xml.ref(:id => "<H&R \"block\">")
90
+ assert_equal %{<ref id="&lt;H&amp;R &quot;block&quot;&gt;"/>}, @xml.target!
91
+ end
92
+
93
+ def test_mixed_attribute_escaping_with_nested_builders
94
+ x = Builder::XmlMarkup.new(:target=>@xml)
95
+ @xml.ref(:id=>:"H&amp;R") {
96
+ x.element(:tag=>"Long&Short")
97
+ }
98
+ assert_equal "<ref id=\"H&amp;R\"><element tag=\"Long&amp;Short\"/></ref>",
99
+ @xml.target!
100
+ end
101
+
102
+ def test_multiple_attributes
103
+ @xml.ref(:id => 12, :name => "bill")
104
+ assert_match %r{^<ref( id="12"| name="bill"){2}/>$}, @xml.target!
105
+ end
106
+
107
+ def test_attributes_with_text
108
+ @xml.a("link", :href=>"http://onestepback.org")
109
+ assert_equal %{<a href="http://onestepback.org">link</a>}, @xml.target!
110
+ end
111
+
112
+ def test_attributes_with_newlines
113
+ @xml.abbr("W3C", :title=>"World\nWide\rWeb\r\nConsortium")
114
+ assert_equal %{<abbr title="World&#10;Wide&#13;Web&#13;&#10;Consortium">W3C</abbr>},
115
+ @xml.target!
116
+ end
117
+
118
+ def test_complex
119
+ @xml.body(:bg=>"#ffffff") { |x|
120
+ x.title("T", :style=>"red")
121
+ }
122
+ assert_equal %{<body bg="#ffffff"><title style="red">T</title></body>}, @xml.target!
123
+ end
124
+
125
+ def test_funky_symbol
126
+ @xml.tag!("non-ruby-token", :id=>1) { |x| x.ok }
127
+ assert_equal %{<non-ruby-token id="1"><ok/></non-ruby-token>}, @xml.target!
128
+ end
129
+
130
+ def test_tag_can_handle_private_method
131
+ @xml.tag!("loop", :id=>1) { |x| x.ok }
132
+ assert_equal %{<loop id="1"><ok/></loop>}, @xml.target!
133
+ end
134
+
135
+ def test_no_explicit_marker
136
+ @xml.p { |x| x.b("HI") }
137
+ assert_equal "<p><b>HI</b></p>", @xml.target!
138
+ end
139
+
140
+ def test_reference_local_vars
141
+ n = 3
142
+ @xml.ol { |x| n.times { x.li(n) } }
143
+ assert_equal "<ol><li>3</li><li>3</li><li>3</li></ol>", @xml.target!
144
+ end
145
+
146
+ def test_reference_methods
147
+ @xml.title { |x| x.a { x.b(_name) } }
148
+ assert_equal "<title><a><b>bob</b></a></title>", @xml.target!
149
+ end
150
+
151
+ def test_append_text
152
+ @xml.p { |x| x.br; x.text! "HI" }
153
+ assert_equal "<p><br/>HI</p>", @xml.target!
154
+ end
155
+
156
+ def test_ambiguous_markup
157
+ ex = assert_raise(ArgumentError) {
158
+ @xml.h1("data1") { b }
159
+ }
160
+ assert_match(/\btext\b/, ex.message)
161
+ assert_match(/\bblock\b/, ex.message)
162
+ end
163
+
164
+ def test_capitalized_method
165
+ @xml.P { |x| x.B("hi"); x.BR(); x.EM { x.text! "world" } }
166
+ assert_equal "<P><B>hi</B><BR/><EM>world</EM></P>", @xml.target!
167
+ end
168
+
169
+ def test_escaping
170
+ @xml.div { |x| x.text! "<hi>"; x.em("H&R Block") }
171
+ assert_equal %{<div>&lt;hi&gt;<em>H&amp;R Block</em></div>}, @xml.target!
172
+ end
173
+
174
+ def test_nil
175
+ b = Builder::XmlMarkup.new
176
+ b.tag! "foo", nil
177
+ assert_equal %{<foo/>}, b.target!
178
+ end
179
+
180
+ def test_nil_without_explicit_nil_handling
181
+ b = Builder::XmlMarkup.new(:explicit_nil_handling => false)
182
+ b.tag! "foo", nil
183
+ assert_equal %{<foo/>}, b.target!
184
+ end
185
+
186
+ def test_nil_with_explicit_nil_handling
187
+ b = Builder::XmlMarkup.new(:explicit_nil_handling => true)
188
+ b.tag! "foo", nil
189
+ assert_equal %{<foo nil="true"/>}, b.target!
190
+ end
191
+
192
+ def test_non_escaping
193
+ @xml.div("ns:xml"=>:"&xml;") { |x| x << "<h&i>"; x.em("H&R Block") }
194
+ assert_equal %{<div ns:xml="&xml;"><h&i><em>H&amp;R Block</em></div>}, @xml.target!
195
+ end
196
+
197
+ def test_return_value
198
+ str = @xml.x("men")
199
+ assert_equal @xml.target!, str
200
+ end
201
+
202
+ def test_stacked_builders
203
+ b = Builder::XmlMarkup.new( :target => @xml )
204
+ b.div { @xml.span { @xml.a("text", :href=>"ref") } }
205
+ assert_equal "<div><span><a href=\"ref\">text</a></span></div>", @xml.target!
206
+ end
207
+
208
+ def _name
209
+ "bob"
210
+ end
211
+ end
212
+
213
+ class TestAttributeEscaping < Builder::Test
214
+
215
+ def setup
216
+ @xml = Builder::XmlMarkup.new
217
+ end
218
+
219
+ def test_element_gt
220
+ @xml.title('1<2')
221
+ assert_equal '<title>1&lt;2</title>', @xml.target!
222
+ end
223
+
224
+ def test_element_amp
225
+ @xml.title('AT&T')
226
+ assert_equal '<title>AT&amp;T</title>', @xml.target!
227
+ end
228
+
229
+ def test_element_amp2
230
+ @xml.title('&amp;')
231
+ assert_equal '<title>&amp;amp;</title>', @xml.target!
232
+ end
233
+
234
+ def test_attr_less
235
+ @xml.a(:title => '2>1')
236
+ assert_equal '<a title="2&gt;1"/>', @xml.target!
237
+ end
238
+
239
+ def test_attr_amp
240
+ @xml.a(:title => 'AT&T')
241
+ assert_equal '<a title="AT&amp;T"/>', @xml.target!
242
+ end
243
+
244
+ def test_attr_quot
245
+ @xml.a(:title => '"x"')
246
+ assert_equal '<a title="&quot;x&quot;"/>', @xml.target!
247
+ end
248
+
249
+ end
250
+
251
+ class TestNameSpaces < Builder::Test
252
+ def setup
253
+ @xml = Builder::XmlMarkup.new(:indent=>2)
254
+ end
255
+
256
+ def test_simple_name_spaces
257
+ @xml.rdf :RDF
258
+ assert_equal "<rdf:RDF/>\n", @xml.target!
259
+ end
260
+
261
+ def test_long
262
+ xml = Builder::XmlMarkup.new(:indent=>2)
263
+ xml.instruct!
264
+ xml.rdf :RDF,
265
+ "xmlns:rdf" => :"&rdf;",
266
+ "xmlns:rdfs" => :"&rdfs;",
267
+ "xmlns:xsd" => :"&xsd;",
268
+ "xmlns:owl" => :"&owl;" do
269
+ xml.owl :Class, :'rdf:ID'=>'Bird' do
270
+ xml.rdfs :label, 'bird'
271
+ xml.rdfs :subClassOf do
272
+ xml.owl :Restriction do
273
+ xml.owl :onProperty, 'rdf:resource'=>'#wingspan'
274
+ xml.owl :maxCardinality,1,'rdf:datatype'=>'&xsd;nonNegativeInteger'
275
+ end
276
+ end
277
+ end
278
+ end
279
+ assert_match(/^<\?xml/, xml.target!)
280
+ assert_match(/\n<rdf:RDF/m, xml.target!)
281
+ assert_match(/xmlns:rdf="&rdf;"/m, xml.target!)
282
+ assert_match(/<owl:Restriction>/m, xml.target!)
283
+ end
284
+
285
+ def test_ensure
286
+ xml = Builder::XmlMarkup.new
287
+ xml.html do
288
+ xml.body do
289
+ begin
290
+ xml.p do
291
+ raise Exception.new('boom')
292
+ end
293
+ rescue Exception => e
294
+ xml.pre e
295
+ end
296
+ end
297
+ end
298
+ assert_match %r{<p>}, xml.target!
299
+ assert_match %r{</p>}, xml.target!
300
+ end
301
+ end
302
+
303
+ class TestDeclarations < Builder::Test
304
+ def setup
305
+ @xml = Builder::XmlMarkup.new(:indent=>2)
306
+ end
307
+
308
+ def test_declare
309
+ @xml.declare! :element
310
+ assert_equal "<!element>\n", @xml.target!
311
+ end
312
+
313
+ def test_bare_arg
314
+ @xml.declare! :element, :arg
315
+ assert_equal"<!element arg>\n", @xml.target!
316
+ end
317
+
318
+ def test_string_arg
319
+ @xml.declare! :element, "string"
320
+ assert_equal"<!element \"string\">\n", @xml.target!
321
+ end
322
+
323
+ def test_mixed_args
324
+ @xml.declare! :element, :x, "y", :z, "-//OASIS//DTD DocBook XML//EN"
325
+ assert_equal "<!element x \"y\" z \"-//OASIS//DTD DocBook XML//EN\">\n", @xml.target!
326
+ end
327
+
328
+ def test_nested_declarations
329
+ @xml = Builder::XmlMarkup.new
330
+ @xml.declare! :DOCTYPE, :chapter do |x|
331
+ x.declare! :ELEMENT, :chapter, "(title,para+)".intern
332
+ end
333
+ assert_equal "<!DOCTYPE chapter [<!ELEMENT chapter (title,para+)>]>", @xml.target!
334
+ end
335
+
336
+ def test_nested_indented_declarations
337
+ @xml.declare! :DOCTYPE, :chapter do |x|
338
+ x.declare! :ELEMENT, :chapter, "(title,para+)".intern
339
+ end
340
+ assert_equal "<!DOCTYPE chapter [\n <!ELEMENT chapter (title,para+)>\n]>\n", @xml.target!
341
+ end
342
+
343
+ def test_complex_declaration
344
+ @xml.declare! :DOCTYPE, :chapter do |x|
345
+ x.declare! :ELEMENT, :chapter, "(title,para+)".intern
346
+ x.declare! :ELEMENT, :title, "(#PCDATA)".intern
347
+ x.declare! :ELEMENT, :para, "(#PCDATA)".intern
348
+ end
349
+ expected = %{<!DOCTYPE chapter [
350
+ <!ELEMENT chapter (title,para+)>
351
+ <!ELEMENT title (#PCDATA)>
352
+ <!ELEMENT para (#PCDATA)>
353
+ ]>
354
+ }
355
+ assert_equal expected, @xml.target!
356
+ end
357
+ end
358
+
359
+
360
+ class TestSpecialMarkup < Builder::Test
361
+ def setup
362
+ @xml = Builder::XmlMarkup.new(:indent=>2)
363
+ end
364
+
365
+ def test_comment
366
+ @xml.comment!("COMMENT")
367
+ assert_equal "<!-- COMMENT -->\n", @xml.target!
368
+ end
369
+
370
+ def test_indented_comment
371
+ @xml.p { @xml.comment! "OK" }
372
+ assert_equal "<p>\n <!-- OK -->\n</p>\n", @xml.target!
373
+ end
374
+
375
+ def test_instruct
376
+ @xml.instruct! :abc, :version=>"0.9"
377
+ assert_equal "<?abc version=\"0.9\"?>\n", @xml.target!
378
+ end
379
+
380
+ def test_indented_instruct
381
+ @xml.p { @xml.instruct! :xml }
382
+ assert_match %r{<p>\n <\?xml version="1.0" encoding="UTF-8"\?>\n</p>\n},
383
+ @xml.target!
384
+ end
385
+
386
+ def test_instruct_without_attributes
387
+ @xml.instruct! :zz
388
+ assert_equal "<?zz?>\n", @xml.target!
389
+ end
390
+
391
+ def test_xml_instruct
392
+ @xml.instruct!
393
+ assert_match(/^<\?xml version="1.0" encoding="UTF-8"\?>$/, @xml.target!)
394
+ end
395
+
396
+ def test_xml_instruct_with_overrides
397
+ @xml.instruct! :xml, :encoding=>"UCS-2"
398
+ assert_match(/^<\?xml version="1.0" encoding="UCS-2"\?>$/, @xml.target!)
399
+ end
400
+
401
+ def test_xml_instruct_with_standalong
402
+ @xml.instruct! :xml, :encoding=>"UCS-2", :standalone=>"yes"
403
+ assert_match(/^<\?xml version="1.0" encoding="UCS-2" standalone="yes"\?>$/, @xml.target!)
404
+ end
405
+
406
+ def test_no_blocks
407
+ assert_raise(Builder::IllegalBlockError) do
408
+ @xml.instruct! { |x| x.hi }
409
+ end
410
+ assert_raise(Builder::IllegalBlockError) do
411
+ @xml.comment!(:element) { |x| x.hi }
412
+ end
413
+ end
414
+
415
+ def test_cdata
416
+ @xml.cdata!("TEST")
417
+ assert_equal "<![CDATA[TEST]]>\n", @xml.target!
418
+ end
419
+
420
+ def test_cdata_with_ampersand
421
+ @xml.cdata!("TEST&CHECK")
422
+ assert_equal "<![CDATA[TEST&CHECK]]>\n", @xml.target!
423
+ end
424
+
425
+ def test_cdata_with_included_close
426
+ @xml.cdata!("TEST]]>CHECK")
427
+ assert_equal "<![CDATA[TEST]]]]><![CDATA[>CHECK]]>\n", @xml.target!
428
+ end
429
+ end
430
+
431
+ class TestIndentedXmlMarkup < Builder::Test
432
+ def setup
433
+ @xml = Builder::XmlMarkup.new(:indent=>2)
434
+ end
435
+
436
+ def test_one_level
437
+ @xml.ol { |x| x.li "text" }
438
+ assert_equal "<ol>\n <li>text</li>\n</ol>\n", @xml.target!
439
+ end
440
+
441
+ def test_two_levels
442
+ @xml.p { |x|
443
+ x.ol { x.li "text" }
444
+ x.br
445
+ }
446
+ assert_equal "<p>\n <ol>\n <li>text</li>\n </ol>\n <br/>\n</p>\n", @xml.target!
447
+ end
448
+
449
+ def test_initial_level
450
+ @xml = Builder::XmlMarkup.new(:indent=>2, :margin=>4)
451
+ @xml.name { |x| x.first("Jim") }
452
+ assert_equal " <name>\n <first>Jim</first>\n </name>\n", @xml.target!
453
+ end
454
+
455
+ class TestUtfMarkup < Builder::Test
456
+ if ! String.method_defined?(:encode)
457
+ def setup
458
+ @old_kcode = $KCODE
459
+ end
460
+
461
+ def teardown
462
+ $KCODE = @old_kcode
463
+ end
464
+
465
+ def test_use_entities_if_no_encoding_is_given_and_kcode_is_none
466
+ $KCODE = 'NONE'
467
+ xml = Builder::XmlMarkup.new
468
+ xml.p("\xE2\x80\x99")
469
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
470
+ end
471
+
472
+ def test_use_entities_if_encoding_is_utf_but_kcode_is_not
473
+ $KCODE = 'NONE'
474
+ xml = Builder::XmlMarkup.new
475
+ xml.instruct!(:xml, :encoding => 'UTF-8')
476
+ xml.p("\xE2\x80\x99")
477
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
478
+ end
479
+ else
480
+ # change in behavior. As there is no $KCODE anymore, the default
481
+ # moves from "does not understand utf-8" to "supports utf-8".
482
+
483
+ def test_use_entities_if_no_encoding_is_given_and_kcode_is_none
484
+ xml = Builder::XmlMarkup.new
485
+ xml.p("\xE2\x80\x99")
486
+ assert_match("<p>\u2019</p>", xml.target!) #
487
+ end
488
+
489
+ def test_use_entities_if_encoding_is_utf_but_kcode_is_not
490
+ xml = Builder::XmlMarkup.new
491
+ xml.instruct!(:xml, :encoding => 'UTF-8')
492
+ xml.p("\xE2\x80\x99")
493
+ assert_match("<p>\u2019</p>", xml.target!) #
494
+ end
495
+ end
496
+
497
+ def encode string, encoding
498
+ if !String.method_defined?(:encode)
499
+ $KCODE = encoding
500
+ string
501
+ elsif encoding == 'UTF8'
502
+ string.force_encoding('UTF-8')
503
+ else
504
+ string
505
+ end
506
+ end
507
+
508
+ def test_use_entities_if_kcode_is_utf_but_encoding_is_dummy_encoding
509
+ xml = Builder::XmlMarkup.new
510
+ xml.instruct!(:xml, :encoding => 'UTF-16')
511
+ xml.p(encode("\xE2\x80\x99", 'UTF8'))
512
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
513
+ end
514
+
515
+ def test_use_entities_if_kcode_is_utf_but_encoding_is_unsupported_encoding
516
+ xml = Builder::XmlMarkup.new
517
+ xml.instruct!(:xml, :encoding => 'UCS-2')
518
+ xml.p(encode("\xE2\x80\x99", 'UTF8'))
519
+ assert_match(%r(<p>&#8217;</p>), xml.target!) #
520
+ end
521
+
522
+ def test_use_utf8_if_encoding_defaults_and_kcode_is_utf8
523
+ xml = Builder::XmlMarkup.new
524
+ xml.p(encode("\xE2\x80\x99",'UTF8'))
525
+ assert_equal encode("<p>\xE2\x80\x99</p>",'UTF8'), xml.target!
526
+ end
527
+
528
+ def test_use_utf8_if_both_encoding_and_kcode_are_utf8
529
+ xml = Builder::XmlMarkup.new
530
+ xml.instruct!(:xml, :encoding => 'UTF-8')
531
+ xml.p(encode("\xE2\x80\x99",'UTF8'))
532
+ assert_match encode("<p>\xE2\x80\x99</p>",'UTF8'), xml.target!
533
+ end
534
+
535
+ def test_use_utf8_if_both_encoding_and_kcode_are_utf8_with_lowercase
536
+ xml = Builder::XmlMarkup.new
537
+ xml.instruct!(:xml, :encoding => 'utf-8')
538
+ xml.p(encode("\xE2\x80\x99",'UTF8'))
539
+ assert_match encode("<p>\xE2\x80\x99</p>",'UTF8'), xml.target!
540
+ end
541
+ end
542
+
543
+ class TestXmlEvents < Builder::Test
544
+ def setup
545
+ @handler = EventHandler.new
546
+ @xe = Builder::XmlEvents.new(:target=>@handler)
547
+ end
548
+
549
+ def test_simple
550
+ @xe.p
551
+ assert_equal [:start, :p, nil], @handler.events.shift
552
+ assert_equal [:end, :p], @handler.events.shift
553
+ end
554
+
555
+ def test_text
556
+ @xe.p("HI")
557
+ assert_equal [:start, :p, nil], @handler.events.shift
558
+ assert_equal [:text, "HI"], @handler.events.shift
559
+ assert_equal [:end, :p], @handler.events.shift
560
+ end
561
+
562
+ def test_attributes
563
+ @xe.p("id"=>"2")
564
+ ev = @handler.events.shift
565
+ assert_equal [:start, :p], ev[0,2]
566
+ assert_equal "2", ev[2]['id']
567
+ assert_equal [:end, :p], @handler.events.shift
568
+ end
569
+
570
+ def test_indented
571
+ @xml = Builder::XmlEvents.new(:indent=>2, :target=>@handler)
572
+ @xml.p { |x| x.b("HI") }
573
+ assert_equal [:start, :p, nil], @handler.events.shift
574
+ assert_equal "\n ", pop_text
575
+ assert_equal [:start, :b, nil], @handler.events.shift
576
+ assert_equal "HI", pop_text
577
+ assert_equal [:end, :b], @handler.events.shift
578
+ assert_equal "\n", pop_text
579
+ assert_equal [:end, :p], @handler.events.shift
580
+ end
581
+
582
+ def pop_text
583
+ result = ''
584
+ while ! @handler.events.empty? && @handler.events[0][0] == :text
585
+ result << @handler.events[0][1]
586
+ @handler.events.shift
587
+ end
588
+ result
589
+ end
590
+
591
+ class EventHandler
592
+ attr_reader :events
593
+ def initialize
594
+ @events = []
595
+ end
596
+
597
+ def start_tag(sym, attrs)
598
+ @events << [:start, sym, attrs]
599
+ end
600
+
601
+ def end_tag(sym)
602
+ @events << [:end, sym]
603
+ end
604
+
605
+ def text(txt)
606
+ @events << [:text, txt]
607
+ end
608
+ end
609
+ end
610
+
611
+ end